SGF-395 - Allow Spring JavaConfig @Configuration classes to be registered and used to configure the (AnnotationConfig)ApplicationContext created by the SpringContextBootstrappingInitializer.
(cherry picked from commit c492a94a4c05b4697aa0a39920a48dd283e0c27e) Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -17,7 +17,10 @@
|
||||
package org.springframework.data.gemfire.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -32,6 +35,7 @@ import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.SimpleApplicationEventMulticaster;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -71,6 +75,8 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
|
||||
/* package-private */ static volatile ContextRefreshedEvent contextRefreshedEvent;
|
||||
|
||||
private static final List<Class<?>> registeredAnnotatedClasses = new CopyOnWriteArrayList<Class<?>>();
|
||||
|
||||
protected final Log logger = initLogger();
|
||||
|
||||
/**
|
||||
@@ -81,7 +87,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
*/
|
||||
public static synchronized ConfigurableApplicationContext getApplicationContext() {
|
||||
Assert.state(applicationContext != null, "The Spring ApplicationContext has not been properly configured and initialized!");
|
||||
Assert.state(applicationContext != null, "The Spring ApplicationContext was not configured and initialized properly!");
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@@ -97,7 +103,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
* @see org.springframework.context.event.ContextRefreshedEvent
|
||||
*/
|
||||
protected static void notifyOnExistingContextRefreshedEvent(final ApplicationListener<ContextRefreshedEvent> listener) {
|
||||
protected static void notifyOnExistingContextRefreshedEvent(ApplicationListener<ContextRefreshedEvent> listener) {
|
||||
synchronized (applicationEventNotifier) {
|
||||
if (contextRefreshedEvent != null) {
|
||||
listener.onApplicationEvent(contextRefreshedEvent);
|
||||
@@ -121,7 +127,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
|
||||
* #addApplicationListener(org.springframework.context.ApplicationListener)
|
||||
*/
|
||||
public static <T extends ApplicationListener<ContextRefreshedEvent>> T register(final T listener) {
|
||||
public static <T extends ApplicationListener<ContextRefreshedEvent>> T register(T listener) {
|
||||
synchronized (applicationEventNotifier) {
|
||||
applicationEventNotifier.addApplicationListener(listener);
|
||||
notifyOnExistingContextRefreshedEvent(listener);
|
||||
@@ -130,6 +136,19 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified Spring annotated POJO class, which will be used to configure and initialize
|
||||
* the Spring ApplicationContext.
|
||||
*
|
||||
* @param annotatedClass the Spring annotated (@Configuration) POJO class to register.
|
||||
* @return a boolean value indicating whether the Spring annotated POJO class was successfully registered.
|
||||
* @see #unregister(Class)
|
||||
*/
|
||||
public static boolean register(Class<?> annotatedClass) {
|
||||
Assert.notNull(annotatedClass, "the Spring annotated class to register must not be null");
|
||||
return registeredAnnotatedClasses.add(annotatedClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-registers the Spring ApplicationListener from this SpringContextBootstrappingInitializer in order to stop
|
||||
* receiving ApplicationEvents on Spring context refreshes.
|
||||
@@ -144,7 +163,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
|
||||
* #removeApplicationListener(org.springframework.context.ApplicationListener)
|
||||
*/
|
||||
public static <T extends ApplicationListener<ContextRefreshedEvent>> T unregister(final T listener) {
|
||||
public static <T extends ApplicationListener<ContextRefreshedEvent>> T unregister(T listener) {
|
||||
synchronized (applicationEventNotifier) {
|
||||
applicationEventNotifier.removeApplicationListener(listener);
|
||||
}
|
||||
@@ -152,6 +171,18 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Un-registers the specified Spring annotated POJO class used to configure and initialize
|
||||
* the Spring ApplicationContext.
|
||||
*
|
||||
* @param annotatedClass the Spring annotated (@Configuration) POJO class to unregister.
|
||||
* @return a boolean value indicating whether the Spring annotated POJO class was successfully un-registered.
|
||||
* @see #register(Class)
|
||||
*/
|
||||
public static boolean unregister(Class<?> annotatedClass) {
|
||||
return registeredAnnotatedClasses.remove(annotatedClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization method for the logger used to log important messages from this initializer.
|
||||
*
|
||||
@@ -163,25 +194,6 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
return LogFactory.getLog(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates (constructs and configures) a ConfigurableApplicationContext instance based on the specified locations
|
||||
* of the context configuration meta-data files. The created ConfigurableApplicationContext is not automatically
|
||||
* "refreshed" and therefore must be "refreshed" by the caller manually.
|
||||
*
|
||||
* @param configLocations a String array indicating the locations of the context configuration meta-data files
|
||||
* used to configure the ConfigurableApplicationContext instance.
|
||||
* @return a newly constructed and configured instance of the ConfigurableApplicationContext class. Note, the
|
||||
* "refresh" method must be called manually before using the context.
|
||||
* @throws IllegalArgumentException if the configLocations parameter argument is null or empty.
|
||||
* @see #createApplicationContext(String[], String[])
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
*/
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations) {
|
||||
Assert.notEmpty(configLocations, "'configLocations' must be specified to construct and configure"
|
||||
+ " an instance of the ClassPathXmlApplicationContext.");
|
||||
return createApplicationContext(null, configLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -206,23 +218,29 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext#scan(String...)
|
||||
* @see org.springframework.context.support.ClassPathXmlApplicationContext
|
||||
*/
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
final String[] configLocations) {
|
||||
protected ConfigurableApplicationContext createApplicationContext(String[] basePackages, String[] configLocations) {
|
||||
if (!ObjectUtils.isEmpty(configLocations)) {
|
||||
return new ClassPathXmlApplicationContext(configLocations, false);
|
||||
return createApplicationContext(configLocations);
|
||||
}
|
||||
else {
|
||||
Assert.notEmpty(basePackages, "'basePackages' or 'configLocations' must be specified"
|
||||
+ " to construct and configure an instance of the ConfigurableApplicationContext.");
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.scan(basePackages);
|
||||
return applicationContext;
|
||||
Assert.isTrue(isConfigurable(basePackages, configLocations, registeredAnnotatedClasses),
|
||||
"'basePackages', 'configLocations' or 'AnnotatedClasses' 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc) - used for testing purposes only */
|
||||
ConfigurableApplicationContext createApplicationContext(String[] configLocations) {
|
||||
return (ObjectUtils.isEmpty(configLocations) ? new AnnotationConfigApplicationContext()
|
||||
: new ClassPathXmlApplicationContext(configLocations, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given ApplicationContext by registering this SpringContextBootstrappingInitializer as an
|
||||
* ApplicationListener and registering a Runtime shutdown hook.
|
||||
* ApplicationListener and registering a runtime shutdown hook.
|
||||
*
|
||||
* @param applicationContext the ConfigurableApplicationContext to initialize.
|
||||
* @return the initialized ApplicationContext.
|
||||
@@ -231,8 +249,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
|
||||
* @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null!
|
||||
*/
|
||||
protected ConfigurableApplicationContext initApplicationContext(
|
||||
final ConfigurableApplicationContext applicationContext) {
|
||||
protected ConfigurableApplicationContext initApplicationContext(ConfigurableApplicationContext applicationContext) {
|
||||
Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null!");
|
||||
applicationContext.addApplicationListener(this);
|
||||
applicationContext.registerShutdownHook();
|
||||
@@ -248,24 +265,69 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#refresh()
|
||||
* @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null!
|
||||
*/
|
||||
protected ConfigurableApplicationContext refreshApplicationContext(
|
||||
final ConfigurableApplicationContext applicationContext) {
|
||||
protected ConfigurableApplicationContext refreshApplicationContext(ConfigurableApplicationContext applicationContext) {
|
||||
Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null!");
|
||||
applicationContext.refresh();
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private boolean isConfigurable(String[] basePackages, String[] contextConfigLocations,
|
||||
Collection<Class<?>> annotatedClasses) {
|
||||
return !(ObjectUtils.isEmpty(basePackages) && ObjectUtils.isEmpty(contextConfigLocations)
|
||||
&& CollectionUtils.isEmpty(annotatedClasses));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the the ID of the Spring ApplicationContext in a null-safe manner.
|
||||
* Null-safe operation used to get the ID of the Spring ApplicationContext.
|
||||
*
|
||||
* @param applicationContext the Spring ApplicationContext to retrieve the ID for.
|
||||
* @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()
|
||||
*/
|
||||
protected String nullSafeGetApplicationContextId(final ApplicationContext applicationContext) {
|
||||
String nullSafeGetApplicationContextId(ApplicationContext applicationContext) {
|
||||
return (applicationContext != null ? applicationContext.getId() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given Spring annotated (@Configuration) POJO classes with the specified
|
||||
* AnnotationConfigApplicationContext.
|
||||
*
|
||||
* @param applicationContext the AnnotationConfigApplicationContext used to register the Spring annotated,
|
||||
* POJO classes.
|
||||
* @param annotatedClasses a Class array of Spring annotated (@Configuration) classes used to configure
|
||||
* and initialize the Spring AnnotationConfigApplicationContext.
|
||||
* @return the given AnnotationConfigApplicationContext.
|
||||
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext#register(Class[])
|
||||
*/
|
||||
AnnotationConfigApplicationContext registerAnnotatedClasses(AnnotationConfigApplicationContext applicationContext,
|
||||
Class<?>[] annotatedClasses) {
|
||||
if (!ObjectUtils.isEmpty(annotatedClasses)) {
|
||||
applicationContext.register(annotatedClasses);
|
||||
}
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures classpath component scanning using the specified base packages on the specified
|
||||
* AnnotationConfigApplicationContext.
|
||||
*
|
||||
* @param applicationContext the AnnotationConfigApplicationContext to setup with classpath component scanning
|
||||
* using the specified base packages.
|
||||
* @param basePackages an array of Strings indicating the base packages to use in the classpath component scan.
|
||||
* @return the given AnnotationConfigApplicationContext.
|
||||
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext#scan(String...)
|
||||
*/
|
||||
AnnotationConfigApplicationContext scanBasePackages(AnnotationConfigApplicationContext applicationContext,
|
||||
String[] basePackages) {
|
||||
if (!ObjectUtils.isEmpty(basePackages)) {
|
||||
applicationContext.scan(basePackages);
|
||||
}
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a Spring ApplicationContext with the given parameters specified with a GemFire <initializer>
|
||||
* block in cache.xml.
|
||||
@@ -288,14 +350,11 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
String basePackages = parameters.getProperty(BASE_PACKAGES_PARAMETER);
|
||||
String contextConfigLocations = parameters.getProperty(CONTEXT_CONFIG_LOCATIONS_PARAMETER);
|
||||
|
||||
Assert.isTrue(StringUtils.hasText(basePackages) || StringUtils.hasText(contextConfigLocations),
|
||||
"Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.");
|
||||
String[] basePackagesArray = StringUtils.delimitedListToStringArray(
|
||||
StringUtils.trimWhitespace(basePackages), COMMA_DELIMITER, CHARS_TO_DELETE);
|
||||
|
||||
String[] basePackagesArray = StringUtils.delimitedListToStringArray(basePackages,
|
||||
COMMA_DELIMITER, CHARS_TO_DELETE);
|
||||
|
||||
String[] contextConfigLocationsArray = StringUtils.delimitedListToStringArray(contextConfigLocations,
|
||||
COMMA_DELIMITER, CHARS_TO_DELETE);
|
||||
String[] contextConfigLocationsArray = StringUtils.delimitedListToStringArray(
|
||||
StringUtils.trimWhitespace(contextConfigLocations), COMMA_DELIMITER, CHARS_TO_DELETE);
|
||||
|
||||
ConfigurableApplicationContext localApplicationContext = refreshApplicationContext(
|
||||
initApplicationContext(createApplicationContext(basePackagesArray, contextConfigLocationsArray)));
|
||||
|
||||
@@ -25,6 +25,7 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -36,6 +37,8 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.gemfire.LazyWiringDeclarableSupport;
|
||||
import org.springframework.data.gemfire.config.GemfireConstants;
|
||||
import org.springframework.data.gemfire.repository.sample.User;
|
||||
@@ -80,7 +83,7 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
protected static final String GEMFIRE_JMX_MANAGER_PORT = "1199";
|
||||
protected static final String GEMFIRE_JMX_MANAGER_START = "true";
|
||||
protected static final String GEMFIRE_MCAST_PORT = "0";
|
||||
protected static final String GEMFIRE_NAME = "SpringContextBootstrappingInitializationIntegrationTest";
|
||||
protected static final String GEMFIRE_NAME = SpringContextBootstrappingInitializerIntegrationTest.class.getSimpleName();
|
||||
protected static final String GEMFIRE_START_LOCATORS = "localhost[11235]";
|
||||
|
||||
@Before
|
||||
@@ -207,16 +210,45 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringContextBootstrappingInitializationUsingBasePackages() {
|
||||
public void testSpringContextBootstrappingInitializerUsingAnnotatedClasses() {
|
||||
SpringContextBootstrappingInitializer.register(TestAppConfig.class);
|
||||
|
||||
new SpringContextBootstrappingInitializer().init(new Properties());
|
||||
|
||||
ConfigurableApplicationContext applicationContext = SpringContextBootstrappingInitializer.getApplicationContext();
|
||||
|
||||
UserDataStoreCacheLoader userDataStoreCacheLoader = applicationContext.getBean(UserDataStoreCacheLoader.class);
|
||||
DataSource userDataSource = applicationContext.getBean(DataSource.class);
|
||||
|
||||
assertSame(UserDataStoreCacheLoader.getInstance(), userDataStoreCacheLoader);
|
||||
assertSame(userDataStoreCacheLoader.getDataSource(), userDataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringContextBootstrappingInitializerUsingBasePackages() {
|
||||
doSpringContextBootstrappingInitializationTest(
|
||||
"cache-with-spring-context-bootstrap-initializer-using-base-packages.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpringContextBootstrappingInitializationUsingContextConfigLocations() {
|
||||
public void testSpringContextBootstrappingInitializerUsingContextConfigLocations() {
|
||||
doSpringContextBootstrappingInitializationTest("cache-with-spring-context-bootstrap-initializer.xml");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class TestAppConfig {
|
||||
|
||||
@Bean
|
||||
public DataSource userDataSource() {
|
||||
return new TestDataSource();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserDataStoreCacheLoader userDataStoreCacheLoader() {
|
||||
return new UserDataStoreCacheLoader();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestDataSource extends DataSourceAdapter {
|
||||
}
|
||||
|
||||
@@ -235,24 +267,19 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
@Autowired
|
||||
private DataSource userDataSource;
|
||||
|
||||
public static UserDataStoreCacheLoader getInstance() {
|
||||
return INSTANCE.get();
|
||||
}
|
||||
|
||||
protected static User createUser(final String username) {
|
||||
protected static User createUser(String username) {
|
||||
return createUser(username, true, Calendar.getInstance(), String.format("%1$s@xcompay.com", username));
|
||||
}
|
||||
|
||||
protected static User createUser(final String username, final Boolean active) {
|
||||
protected static User createUser(String username, Boolean active) {
|
||||
return createUser(username, active, Calendar.getInstance(), String.format("%1$s@xcompay.com", username));
|
||||
}
|
||||
|
||||
protected static User createUser(final String username, final Boolean active, final Calendar since) {
|
||||
protected static User createUser(String username, Boolean active, Calendar since) {
|
||||
return createUser(username, active, since, String.format("%1$s@xcompay.com", username));
|
||||
}
|
||||
|
||||
protected static User createUser(final String username, final Boolean active, final Calendar since,
|
||||
final String email) {
|
||||
protected static User createUser(String username, Boolean active, Calendar since, String email) {
|
||||
User user = new User(username);
|
||||
user.setActive(active);
|
||||
user.setEmail(email);
|
||||
@@ -260,6 +287,10 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
return user;
|
||||
}
|
||||
|
||||
public static UserDataStoreCacheLoader getInstance() {
|
||||
return INSTANCE.get();
|
||||
}
|
||||
|
||||
public UserDataStoreCacheLoader() {
|
||||
Assert.state(INSTANCE.compareAndSet(null, this), String.format("An instance of %1$s was already created!",
|
||||
getClass().getName()));
|
||||
|
||||
@@ -22,24 +22,31 @@ import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Matchers;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
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.ContextClosedEvent;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.ContextStartedEvent;
|
||||
@@ -54,6 +61,7 @@ import org.springframework.context.event.ContextStoppedEvent;
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer
|
||||
* @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest
|
||||
@@ -77,6 +85,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
public void tearDown() {
|
||||
SpringContextBootstrappingInitializer.applicationContext = null;
|
||||
SpringContextBootstrappingInitializer.contextRefreshedEvent = null;
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigOne.class);
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigTwo.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -95,32 +105,20 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
SpringContextBootstrappingInitializer.getApplicationContext();
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertEquals("The Spring ApplicationContext has not been properly configured and initialized!",
|
||||
assertEquals("The Spring ApplicationContext was not configured and initialized properly!",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateApplicationContextWhenBothBasePackagesAndConfigLocationsAreUnspecified() {
|
||||
public void testCreateApplicationContextWhenBasePackagesAndConfigLocationsAreUnspecified() {
|
||||
try {
|
||||
new SpringContextBootstrappingInitializer().createApplicationContext(null, null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("'basePackages' or 'configLocations' must be specified to construct and configure"
|
||||
+" an instance of the ConfigurableApplicationContext.", expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateClassPathXmlApplicationContextWhenConfigLocationsAreUnspecified() {
|
||||
try {
|
||||
new SpringContextBootstrappingInitializer().createApplicationContext(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("'configLocations' must be specified to construct and configure an instance of the ClassPathXmlApplicationContext.",
|
||||
expected.getMessage());
|
||||
assertEquals("'basePackages', 'configLocations' or 'AnnotatedClasses' must be specified in order to"
|
||||
+ " construct and configure an instance of the ConfigurableApplicationContext", expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
@@ -134,8 +132,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
initializer.initApplicationContext(mockApplicationContext);
|
||||
|
||||
verify(mockApplicationContext).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext).registerShutdownHook();
|
||||
verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, times(1)).registerShutdownHook();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -152,11 +150,11 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
@Test
|
||||
public void testRefreshApplicationContext() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testInitApplicationContext");
|
||||
"testRefreshApplicationContext");
|
||||
|
||||
new SpringContextBootstrappingInitializer().refreshApplicationContext(mockApplicationContext);
|
||||
|
||||
verify(mockApplicationContext).refresh();
|
||||
verify(mockApplicationContext, times(1)).refresh();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -186,6 +184,96 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
new SpringContextBootstrappingInitializer().nullSafeGetApplicationContextId(mockApplicationContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterAnnotatedClasses() {
|
||||
AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testRegisterAnnotatedClasses");
|
||||
|
||||
Class<?>[] annotatedClasses = { TestAppConfigOne.class, TestAppConfigTwo.class };
|
||||
|
||||
new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, annotatedClasses);
|
||||
|
||||
verify(mockApplicationContext, times(1)).register(annotatedClasses);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterAnnotatedClassesWithEmptyAnnotatedClassesArray() {
|
||||
AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testRegisterAnnotatedClassesWithEmptyAnnotatedClassesArray");
|
||||
|
||||
new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, new Class<?>[0]);
|
||||
|
||||
verify(mockApplicationContext, never()).register(any(Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanBasePackages() {
|
||||
AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testScanBasePackages");
|
||||
|
||||
String[] basePackages = { "org.example.app", "org.example.plugins" };
|
||||
|
||||
new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, basePackages);
|
||||
|
||||
verify(mockApplicationContext, times(1)).scan(basePackages);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanBasePackagesWithEmptyBasePackagesArray() {
|
||||
AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testScanBasePackages");
|
||||
|
||||
new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, null);
|
||||
|
||||
verify(mockApplicationContext, never()).scan(any(String[].class));
|
||||
}
|
||||
|
||||
private Class<?>[] annotatedClasses(final Class<?>... annotatedClasses) {
|
||||
return argThat(new ArgumentMatcher<Class<?>[]>() {
|
||||
@Override public boolean matches(final Object argument) {
|
||||
assertTrue(argument instanceof Class<?>[]);
|
||||
return Arrays.equals(annotatedClasses, (Class<?>[]) argument);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitWithAnnotatedClasses() {
|
||||
final AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testInitWithAnnotatedClasses");
|
||||
|
||||
doNothing().when(mockApplicationContext).addApplicationListener(any(ApplicationListener.class));
|
||||
doNothing().when(mockApplicationContext).registerShutdownHook();
|
||||
doNothing().when(mockApplicationContext).refresh();
|
||||
doNothing().when(mockApplicationContext).register(Matchers.<Class<?>[]>anyVararg());
|
||||
//doNothing().when(mockApplicationContext).register(annotatedClasses(TestAppConfigOne.class, TestAppConfigTwo.class));
|
||||
|
||||
when(mockApplicationContext.getId()).thenReturn("testInitWithAnnotatedClasses");
|
||||
when(mockApplicationContext.isRunning()).thenReturn(true);
|
||||
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
|
||||
SpringContextBootstrappingInitializer.register(TestAppConfigOne.class);
|
||||
SpringContextBootstrappingInitializer.register(TestAppConfigTwo.class);
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override protected ConfigurableApplicationContext createApplicationContext(String[] configLocations) {
|
||||
return mockApplicationContext;
|
||||
}
|
||||
};
|
||||
|
||||
initializer.init(createParameters("test", "test"));
|
||||
|
||||
verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, times(1)).registerShutdownHook();
|
||||
verify(mockApplicationContext, times(1)).register(TestAppConfigOne.class, TestAppConfigTwo.class);
|
||||
//verify(mockApplicationContext, times(1)).register(annotatedClasses(TestAppConfigOne.class, TestAppConfigTwo.class));
|
||||
//verify(mockApplicationContext, times(1)).register(Matchers.<Class<?>[]>anyVararg());
|
||||
verify(mockApplicationContext, never()).scan(any(String[].class));
|
||||
|
||||
assertEquals(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitWithExistingApplicationContext() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
@@ -200,10 +288,9 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer();
|
||||
|
||||
initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
|
||||
"/path/to/spring/application/context.xml"));
|
||||
initializer.init(createParameters("test", "test"));
|
||||
|
||||
verify(mockApplicationContext, never()).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, never()).addApplicationListener(any(SpringContextBootstrappingInitializer.class));
|
||||
verify(mockApplicationContext, never()).registerShutdownHook();
|
||||
verify(mockApplicationContext, never()).refresh();
|
||||
|
||||
@@ -263,8 +350,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
};
|
||||
|
||||
initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
|
||||
"/path/to/spring/application/context.xml"));
|
||||
initializer.init(createParameters(SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER,
|
||||
"org.example.app"));
|
||||
|
||||
verify(mockNewApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockNewApplicationContext, times(1)).registerShutdownHook();
|
||||
@@ -274,67 +361,71 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInitWhenBothBasePackagesAndContextConfigLocationsParametersAreUnspecified() {
|
||||
public void testInitWhenBasePackagesAndContextConfigLocationsParametersAreUnspecified() throws Throwable {
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
|
||||
try {
|
||||
new SpringContextBootstrappingInitializer().init(createParameters(createParameters(
|
||||
SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, ""),
|
||||
SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, ""));
|
||||
SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, " "));
|
||||
}
|
||||
catch (ApplicationContextException expected) {
|
||||
assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext!"));
|
||||
assertTrue(expected.getCause() instanceof IllegalArgumentException);
|
||||
assertEquals("Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.",
|
||||
expected.getCause().getMessage());
|
||||
throw (IllegalArgumentException) expected.getCause();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testInitWhenApplicationContextIsNotRunning() {
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
|
||||
final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testInitWhenApplicationContextIsNotRunning");
|
||||
|
||||
when(mockApplicationContext.getId()).thenReturn("testInitWhenApplicationContextIsNotRunning");
|
||||
when(mockApplicationContext.isRunning()).thenReturn(false);
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
final String[] configLocations) {
|
||||
return mockApplicationContext;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
|
||||
final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testInitWhenApplicationContextIsNotRunning");
|
||||
|
||||
when(mockApplicationContext.getId()).thenReturn("testInitWhenApplicationContextIsNotRunning");
|
||||
when(mockApplicationContext.isRunning()).thenReturn(false);
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
final String[] configLocations) {
|
||||
return mockApplicationContext;
|
||||
}
|
||||
};
|
||||
|
||||
initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
|
||||
"/path/to/spring/application/context.xml"));
|
||||
|
||||
verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, times(1)).registerShutdownHook();
|
||||
verify(mockApplicationContext, times(1)).refresh();
|
||||
initializer.init(createParameters(SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER,
|
||||
"org.example.app, org.example.plugins"));
|
||||
|
||||
SpringContextBootstrappingInitializer.getApplicationContext();
|
||||
}
|
||||
catch (ApplicationContextException expected) {
|
||||
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 ([/path/to/spring/application/context.xml]) or base packages ([])!",
|
||||
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());
|
||||
throw (IllegalStateException) expected.getCause();
|
||||
}
|
||||
finally {
|
||||
verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, times(1)).registerShutdownHook();
|
||||
verify(mockApplicationContext, times(1)).refresh();
|
||||
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testInitLogsErrors() throws Throwable {
|
||||
final Log mockLogger = mock(Log.class, "testInitLogsErrors.MockLog");
|
||||
final Log mockLog = mock(Log.class, "testInitLogsErrors.MockLog");
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override protected Log initLogger() {
|
||||
return mockLogger;
|
||||
return mockLog;
|
||||
}
|
||||
|
||||
@Override protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
@@ -354,17 +445,17 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
throw expected.getCause();
|
||||
}
|
||||
finally {
|
||||
verify(mockLogger, 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 assertNotifiedWithEvent(final TestApplicationListener listener, final ContextRefreshedEvent expectedEvent) {
|
||||
protected static void assertNotified(TestApplicationListener listener, ContextRefreshedEvent expectedEvent) {
|
||||
assertTrue(listener.isNotified());
|
||||
Assert.assertSame(expectedEvent, listener.getActualEvent());
|
||||
}
|
||||
|
||||
protected static void assertUnnotified(final TestApplicationListener listener) {
|
||||
protected static void assertUnnotified(TestApplicationListener listener) {
|
||||
assertFalse(listener.isNotified());
|
||||
assertNull(listener.getActualEvent());
|
||||
}
|
||||
@@ -383,7 +474,7 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
|
||||
|
||||
assertNotifiedWithEvent(testApplicationListener, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListener, testContextRefreshedEvent);
|
||||
}
|
||||
finally {
|
||||
SpringContextBootstrappingInitializer.unregister(testApplicationListener);
|
||||
@@ -433,13 +524,13 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
assertUnnotified(testApplicationListenerThree);
|
||||
|
||||
ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class,
|
||||
"testRegisterWithOnApplicationEvent"));
|
||||
"testOnApplicationEventWithMultipleRegisteredApplicationListeners"));
|
||||
|
||||
new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
|
||||
|
||||
assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertNotifiedWithEvent(testApplicationListenerThree, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerThree, testContextRefreshedEvent);
|
||||
}
|
||||
finally {
|
||||
SpringContextBootstrappingInitializer.unregister(testApplicationListenerOne);
|
||||
@@ -494,11 +585,11 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
|
||||
|
||||
TestApplicationListener testApplicationListener = new TestApplicationListener(
|
||||
"testNotifyApplicationListenersOnContextRefreshedEventAfterApplicationContextRefreshed");
|
||||
"testNotifyOnExistingContextRefreshedEventAfterContextRefreshed");
|
||||
|
||||
try {
|
||||
testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener);
|
||||
assertNotifiedWithEvent(testApplicationListener, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListener, testContextRefreshedEvent);
|
||||
}
|
||||
finally {
|
||||
SpringContextBootstrappingInitializer.unregister(testApplicationListener);
|
||||
@@ -532,19 +623,19 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
initializer.onApplicationEvent(testContextRefreshedEvent);
|
||||
|
||||
assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertUnnotified(testApplicationListenerTwo);
|
||||
assertUnnotified(testApplicationListenerThree);
|
||||
|
||||
testApplicationListenerTwo = SpringContextBootstrappingInitializer.register(testApplicationListenerTwo);
|
||||
|
||||
assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertUnnotified(testApplicationListenerOne);
|
||||
assertUnnotified(testApplicationListenerThree);
|
||||
|
||||
ContextStoppedEvent contextStoppedEvent = new ContextStoppedEvent(mockApplicationContext);
|
||||
ContextStoppedEvent testContextStoppedEvent = new ContextStoppedEvent(mockApplicationContext);
|
||||
|
||||
initializer.onApplicationEvent(contextStoppedEvent);
|
||||
initializer.onApplicationEvent(testContextStoppedEvent);
|
||||
|
||||
assertUnnotified(testApplicationListenerOne);
|
||||
assertUnnotified(testApplicationListenerTwo);
|
||||
@@ -552,8 +643,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
initializer.onApplicationEvent(testContextRefreshedEvent);
|
||||
|
||||
assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerOne, testContextRefreshedEvent);
|
||||
assertNotified(testApplicationListenerTwo, testContextRefreshedEvent);
|
||||
assertUnnotified(testApplicationListenerThree);
|
||||
|
||||
ContextClosedEvent testContextClosedEvent = new ContextClosedEvent(mockApplicationContext);
|
||||
@@ -577,6 +668,14 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestAppConfigOne {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TestAppConfigTwo {
|
||||
}
|
||||
|
||||
// TODO add additional multi-threaded test cases once MultithreadedTC test framework is added to the SDP project
|
||||
// in order to properly test concurrency of notification and registration during Spring ApplicationContext creation.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user