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 571abe32..c39ab6c1 100644
--- a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java
+++ b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java
@@ -23,7 +23,9 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.ApplicationEventMulticaster;
+import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -41,22 +43,18 @@ import com.gemstone.gemfire.cache.Declarable;
* and initializes the Cache for use.
*
* @author John Blum
- * @see java.util.Properties
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
- * @see org.springframework.context.event.ApplicationEventMulticaster
- * @see org.springframework.context.event.ContextRefreshedEvent
- * @see org.springframework.context.event.SimpleApplicationEventMulticaster
* @see org.springframework.context.support.ClassPathXmlApplicationContext
* @see com.gemstone.gemfire.cache.Declarable
- * @since 1.4.0
- * @see Setting Cache Initializer
+ * @see Setting Cache Initializer
* @see SGF-248
+ * @since 1.4.0
*/
@SuppressWarnings("unused")
-public class SpringContextBootstrappingInitializer implements Declarable, ApplicationListener {
+public class SpringContextBootstrappingInitializer implements Declarable, ApplicationListener {
public static final String BASE_PACKAGES_PARAMETER = "basePackages";
public static final String CONTEXT_CONFIG_LOCATIONS_PARAMETER = "contextConfigLocations";
@@ -64,12 +62,11 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
protected static final String CHARS_TO_DELETE = " \n\t";
protected static final String COMMA_DELIMITER = ",";
+ private static final ApplicationEventMulticaster applicationEventNotifier = new SimpleApplicationEventMulticaster();
+
/* package-private */ static volatile ConfigurableApplicationContext applicationContext;
- // TODO consider whether I should register a TaskExecutor to perform the event notifications in a separate Thread???
- private static final ApplicationEventMulticaster eventNotifier = new SimpleApplicationEventMulticaster();
-
- private static ContextRefreshedEvent contextRefreshedEvent;
+ /* package-private */ static volatile ContextRefreshedEvent contextRefreshedEvent;
/**
* Gets a reference to the Spring ApplicationContext constructed, configured and initialized inside the GemFire
@@ -79,19 +76,40 @@ 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 created!");
+ Assert.state(applicationContext != null, "The Spring ApplicationContext has not been properly configured and initialized!");
return applicationContext;
}
+ /**
+ * Notifies any Spring ApplicationListeners of a current and existing ContextRefreshedEvent if the
+ * ApplicationContext had been previously created, initialized and refreshed before any ApplicationListeners
+ * interested in ContextRefreshedEvents were registered so that application components (such as the
+ * GemFire CacheLoaders extending LazyWiringDeclarableSupport objects) registered late, requiring configuration
+ * (auto-wiring), also get notified and wired accordingly.
+ *
+ * @param listener a Spring ApplicationListener requiring notification of any ContextRefreshedEvents after the
+ * ApplicationContext has already been created, initialized and/or refreshed.
+ * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
+ * @see org.springframework.context.event.ContextRefreshedEvent
+ */
+ protected static void notifyOnExistingContextRefreshedEvent(final ApplicationListener listener) {
+ synchronized (applicationEventNotifier) {
+ if (contextRefreshedEvent != null) {
+ listener.onApplicationEvent(contextRefreshedEvent);
+ }
+ }
+ }
+
/**
* Registers a Spring ApplicationListener to be notified when the Spring ApplicationContext is created by GemFire
- * when instantiating and initializing declared Initializers from the GemFire native configuration file
- * (e.g. cache.xml).
+ * when instantiating and initializing Declarables declared inside the <initializer> block inside GemFire's
+ * cache.xml file.
*
* @param the Class type of the Spring ApplicationListener.
- * @param listener the ApplicationListener to register for ContextRefreshedEvents by this
+ * @param listener the ApplicationListener to register for ContextRefreshedEvents multi-casted by this
* SpringContextBootstrappingInitializer.
* @return the reference to the ApplicationListener for method call chaining purposes.
+ * @see #notifyOnExistingContextRefreshedEvent(org.springframework.context.ApplicationListener)
* @see #unregister(org.springframework.context.ApplicationListener)
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ContextRefreshedEvent
@@ -99,38 +117,16 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
* #addApplicationListener(org.springframework.context.ApplicationListener)
*/
public static > T register(final T listener) {
- synchronized (eventNotifier) {
- eventNotifier.addApplicationListener(listener);
- notifyListenerOfExistingContextRefreshedEvent(listener);
+ synchronized (applicationEventNotifier) {
+ applicationEventNotifier.addApplicationListener(listener);
+ notifyOnExistingContextRefreshedEvent(listener);
}
return listener;
}
/**
- * Notifies any Spring ApplicationListeners of a current and existing ContextRefreshedEvent if the
- * ApplicationContext was previously created, initialized and refreshed before any ApplicationListeners interested
- * in ContextRefreshedEvents get registered so that application components (such as LazyWiringDeclarableSupport
- * objects) arriving late to the game that also require configuration (auto-wiring) get wired accordingly too.
- *
- * @param listener a Spring ApplicationListener requiring notification of any ContextRefreshedEvents after the
- * ApplicationContext has already been created, initialized and/or refreshed.
- * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
- * @see org.springframework.context.event.ContextRefreshedEvent
- */
- protected static void notifyListenerOfExistingContextRefreshedEvent(
- final ApplicationListener listener) {
- synchronized (eventNotifier) {
- // NOTE the null check on the ApplicationContext is not absolutely necessary, but is an extra safety
- // precaution none-the-less.
- if (applicationContext != null && contextRefreshedEvent != null) {
- listener.onApplicationEvent(contextRefreshedEvent);
- }
- }
- }
-
- /**
- * Unregisters the Spring ApplicationListener from this SpringContextBootstrappingInitializer in order to stop
+ * Un-registers the Spring ApplicationListener from this SpringContextBootstrappingInitializer in order to stop
* receiving ApplicationEvents on Spring context refreshes.
*
* @param the Class type of the Spring ApplicationListener.
@@ -144,8 +140,8 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
* #removeApplicationListener(org.springframework.context.ApplicationListener)
*/
public static > T unregister(final T listener) {
- synchronized (eventNotifier) {
- eventNotifier.removeApplicationListener(listener);
+ synchronized (applicationEventNotifier) {
+ applicationEventNotifier.removeApplicationListener(listener);
}
return listener;
@@ -162,29 +158,28 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
* "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.support.ClassPathXmlApplicationContext
+ * @see org.springframework.context.ConfigurableApplicationContext
*/
protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations) {
- Assert.notEmpty(configLocations, "'configLocations' must be specified to construct an instance"
- + " of the ClassPathXmlApplicationContext.");
+ 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
- * specified locations of context configuration meta-data files used to configure the context. The created
- * ConfigurableApplicationContext is not automatically "refreshed" and therefore must be "refreshed"
- * by the caller manually.
+ * specified locations of context configuration meta-data files. The created ConfigurableApplicationContext
+ * is not automatically "refreshed" and therefore must be "refreshed" by the caller manually.
*
- * When basePackages are specified, an instance of AnnotationConfigApplicationContext is returned; otherwise
- * an instance of the ClassPathXmlApplicationContext is initialized with the configLocations and returned.
- * This method prefers the ClassPathXmlApplicationContext to the AnnotationConfigApplicationContext when both
- * basePackages and configLocations are specified.
+ * When basePackages are specified, an instance of AnnotationConfigApplicationContext is constructed and a scan
+ * is performed; otherwise an instance of the ClassPathXmlApplicationContext is initialized with the
+ * configLocations. This method prefers the ClassPathXmlApplicationContext to the
+ * AnnotationConfigApplicationContext when both basePackages and configLocations are specified.
*
- * @param basePackages the base application packages to scan for application @Components and @Configuration classes. *
+ * @param basePackages the base packages to scan for application @Components and @Configuration classes.
* @param configLocations a String array indicating the locations of the context configuration meta-data files
- * used to configure the ConfigurableApplicationContext instance.
+ * used to configure the ClassPathXmlApplicationContext instance.
* @return an instance of ConfigurableApplicationContext configured and initialized with either configLocations
* or the basePackages when configLocations is unspecified. Note, the "refresh" method must be called manually
* before using the context.
@@ -201,8 +196,8 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
return new ClassPathXmlApplicationContext(configLocations, false);
}
else {
- Assert.notEmpty(basePackages, "Either 'basePackages' or 'configLocations' must be specified"
- + " to construct an instance of the ConfigurableApplicationContext.");
+ 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;
@@ -210,46 +205,38 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
}
/**
- * Initializes a Spring ApplicationContext with the given parameters from a GemFire Initializer in GemFire native
- * configuration meta-data (e.g. cache.xml).
+ * Initializes the given ApplicationContext by registering this SpringContextBootstrappingInitializer as an
+ * ApplicationListener and registering a Runtime shutdown hook.
*
- * @param parameters a Properties object containing the configuration parameters and settings defined in the
- * GemFire cache.xml >initializer/< element.
- * @see #createApplicationContext
- * @see java.util.Properties
+ * @param applicationContext the ConfigurableApplicationContext to initialize.
+ * @return the initialized ApplicationContext.
+ * @see org.springframework.context.ConfigurableApplicationContext
+ * @see org.springframework.context.ConfigurableApplicationContext#addApplicationListener(org.springframework.context.ApplicationListener)
+ * @see org.springframework.context.ConfigurableApplicationContext#registerShutdownHook()
+ * @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null!
*/
- @Override
- @SuppressWarnings("null")
- public void init(final Properties parameters) {
- String basePackages = parameters.getProperty(BASE_PACKAGES_PARAMETER);
- String contextConfigLocations = parameters.getProperty(CONTEXT_CONFIG_LOCATIONS_PARAMETER);
+ protected ConfigurableApplicationContext initApplicationContext(
+ final ConfigurableApplicationContext applicationContext) {
+ Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null!");
+ applicationContext.addApplicationListener(this);
+ applicationContext.registerShutdownHook();
+ return applicationContext;
+ }
- Assert.isTrue(StringUtils.hasText(basePackages) || StringUtils.hasText(contextConfigLocations),
- "Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.");
-
- String[] basePackagesArray = StringUtils.delimitedListToStringArray(basePackages,
- COMMA_DELIMITER, CHARS_TO_DELETE);
-
- String[] configLocations = StringUtils.delimitedListToStringArray(contextConfigLocations,
- COMMA_DELIMITER, CHARS_TO_DELETE);
-
- synchronized (SpringContextBootstrappingInitializer.class) {
- Assert.state(applicationContext == null, String.format(
- "A Spring application context with ID (%1$s) has already been created.",
- nullSafeGetApplicationContextId(applicationContext)));
-
- applicationContext = createApplicationContext(basePackagesArray, configLocations);
- Assert.notNull(applicationContext, "The 'created' ConfigurableApplicationContext cannot be null!");
- assert applicationContext != null;
- applicationContext.addApplicationListener(this);
- applicationContext.registerShutdownHook();
- applicationContext.refresh();
-
- Assert.state(applicationContext.isActive(), String.format(
- "The Spring application context (%1$s) has failed to be properly initialized with the following config files (%2$s) or base packages (%3$s)!",
- nullSafeGetApplicationContextId(applicationContext), Arrays.toString(configLocations),
- Arrays.toString(basePackagesArray)));
- }
+ /**
+ * Refreshes the given ApplicationContext making the context active.
+ *
+ * @param applicationContext the ConfigurableApplicationContext to refresh.
+ * @return the refreshed ApplicationContext.
+ * @see org.springframework.context.ConfigurableApplicationContext
+ * @see org.springframework.context.ConfigurableApplicationContext#refresh()
+ * @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null!
+ */
+ protected ConfigurableApplicationContext refreshApplicationContext(
+ final ConfigurableApplicationContext applicationContext) {
+ Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null!");
+ applicationContext.refresh();
+ return applicationContext;
}
/**
@@ -264,21 +251,74 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
}
/**
- * Gets notified when the Spring ApplicationContext gets created and refreshed by GemFire. The handler method
- * proceeds in notifying any other GemFire components that need to be aware that the Spring ApplicationContext
- * now exists and is ready for use, such as other Declarable GemFire objects requiring auto-wiring support, etc.
+ * Initializes a Spring ApplicationContext with the given parameters specified with a GemFire <initializer>
+ * block in cache.xml.
*
- * @param event the ContextRefreshedEvent signaling that the Spring ApplicationContext has been created
- * and refreshed by GemFire.
- * @see org.springframework.context.event.ContextRefreshedEvent
- * @see org.springframework.context.event.ApplicationEventMulticaster
- * #multicastEvent(org.springframework.context.ApplicationEvent)
+ * @param parameters a Properties object containing the configuration parameters and settings defined in the
+ * GemFire cache.xml <initializer> block for the declared SpringContextBootstrappingInitializer
+ * GemFire Declarable object.
+ * @see #createApplicationContext(String[], String[])
+ * @see #initApplicationContext(org.springframework.context.ConfigurableApplicationContext)
+ * @see #refreshApplicationContext(org.springframework.context.ConfigurableApplicationContext)
+ * @see java.util.Properties
*/
@Override
- public void onApplicationEvent(final ContextRefreshedEvent event) {
- synchronized (eventNotifier) {
- contextRefreshedEvent = event;
- eventNotifier.multicastEvent(event);
+ public void init(final Properties parameters) {
+ synchronized (SpringContextBootstrappingInitializer.class) {
+ if (applicationContext == null || !applicationContext.isActive()) {
+ 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(basePackages,
+ COMMA_DELIMITER, CHARS_TO_DELETE);
+
+ String[] contextConfigLocationsArray = StringUtils.delimitedListToStringArray(contextConfigLocations,
+ COMMA_DELIMITER, CHARS_TO_DELETE);
+
+ ConfigurableApplicationContext localApplicationContext = refreshApplicationContext(
+ initApplicationContext(createApplicationContext( basePackagesArray, contextConfigLocationsArray)));
+
+ Assert.state(localApplicationContext.isRunning(), String.format(
+ "The Spring ApplicationContext (%1$s) failed to be properly initialized with the context config files (%2$s) or base packages (%3$s)!",
+ nullSafeGetApplicationContextId(applicationContext), Arrays.toString(contextConfigLocationsArray),
+ Arrays.toString(basePackagesArray)));
+
+ applicationContext = localApplicationContext;
+ }
+ }
+ }
+
+ /**
+ * Gets notified when the Spring ApplicationContext gets created and refreshed by GemFire, once the
+ * <initializer> block is processed and the SpringContextBootstrappingInitializer Declarable component
+ * is initialized. This handler method proceeds in notifying any other GemFire components that need to be aware
+ * that the Spring ApplicationContext now exists and is ready for use, such as other Declarable GemFire objects
+ * requiring auto-wiring support, etc.
+ *
+ * In addition, this method handles the ContextClosedEvent by removing the ApplicationContext reference.
+ *
+ * @param event the ApplicationContextEvent signaling that the Spring ApplicationContext has been created
+ * and refreshed by GemFire, or closed when the JVM process exits.
+ * @see org.springframework.context.event.ContextClosedEvent
+ * @see org.springframework.context.event.ContextRefreshedEvent
+ * @see org.springframework.context.event.ApplicationEventMulticaster
+ * #multicastEvent(org.springframework.context.ApplicationEvent)
+ */
+ @Override
+ public void onApplicationEvent(final ApplicationContextEvent event) {
+ if (event instanceof ContextRefreshedEvent) {
+ synchronized (applicationEventNotifier) {
+ contextRefreshedEvent = (ContextRefreshedEvent) event;
+ applicationEventNotifier.multicastEvent(event);
+ }
+ }
+ else if (event instanceof ContextClosedEvent) {
+ synchronized (applicationEventNotifier) {
+ contextRefreshedEvent = null;
+ }
}
}
diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java
index 905ace5f..1b94b000 100644
--- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java
+++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java
@@ -24,9 +24,10 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Calendar;
-import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.sql.DataSource;
@@ -69,14 +70,17 @@ import com.gemstone.gemfire.cache.Region;
@SuppressWarnings("unused")
public class SpringContextBootstrappingInitializerIntegrationTest {
- private static final long CACHE_CLOSE_TIMEOUT = 15000l; // 15 seconds
+ private static final long CACHE_CLOSE_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
private static final Object MUTEX_LOCK = new Object();
protected static final String GEMFIRE_LOCATORS = "localhost[11235]";
- protected static final String GEMFIRE_LOG_LEVEL = "config";
+ protected static final String GEMFIRE_LOG_LEVEL = "warning";
+ protected static final String GEMFIRE_JMX_MANAGER = "true";
+ 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 = "SpringContextBootstrappingInitializationTest";
+ protected static final String GEMFIRE_NAME = "SpringContextBootstrappingInitializationIntegrationTest";
protected static final String GEMFIRE_START_LOCATORS = "localhost[11235]";
@Before
@@ -99,7 +103,7 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
}
}
- fail(String.format("The Cache instance was not properly closed and shutdown by the timeout of %1$d seconds!%n",
+ fail(String.format("The Cache instance was not properly closed in the allotted timeout of %1$d seconds!%n",
(CACHE_CLOSE_TIMEOUT / 1000)));
}
catch (CacheClosedException ignore) {
@@ -108,7 +112,7 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
@After
public void tearDown() {
- SpringContextBootstrappingInitializer.applicationContext = null;
+ SpringContextBootstrappingInitializer.getApplicationContext().close();
UserDataStoreCacheLoader.INSTANCE.set(null);
tearDownCache();
}
@@ -145,15 +149,18 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
protected void doSpringContextBootstrappingInitializationTest(final String cacheXmlFile) {
Cache gemfireCache = new CacheFactory()
+ .set("name", GEMFIRE_NAME)
+ .set("mcast-port", GEMFIRE_MCAST_PORT)
+ .set("log-level", GEMFIRE_LOG_LEVEL)
.set("cache-xml-file", cacheXmlFile)
//.set("locators", GEMFIRE_LOCATORS)
- .set("log-level", GEMFIRE_LOG_LEVEL)
- .set("mcast-port", GEMFIRE_MCAST_PORT)
- .set("name", GEMFIRE_NAME)
//.set("start-locator", GEMFIRE_LOCATORS)
+ //.set("jmx-manager", GEMFIRE_JMX_MANAGER)
+ //.set("jmx-manager-port", GEMFIRE_JMX_MANAGER_PORT)
+ //.set("jmx-manager-start", GEMFIRE_JMX_MANAGER_START)
.create();
- assertNotNull("The GemFire Cache was not properly created or initialized!", gemfireCache);
+ assertNotNull("The GemFire Cache was not properly created and initialized!", gemfireCache);
assertFalse("The GemFire Cache is closed!", gemfireCache.isClosed());
Set> rootRegions = gemfireCache.rootRegions();
@@ -184,7 +191,6 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
// NOTE a GemFire declared component initialized by Spring!
UserDataStoreCacheLoader usersCacheLoader = UserDataStoreCacheLoader.getInstance();
- assertNotNull(usersCacheLoader);
assertSame(userDataSource, usersCacheLoader.getDataSource());
Region users = gemfireCache.getRegion("/Users");
@@ -200,17 +206,17 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
assertEquals(3, users.size());
}
- @Test
- public void testSpringContextBootstrappingInitialization() {
- doSpringContextBootstrappingInitializationTest("cache-with-spring-context-bootstrap-initializer.xml");
- }
-
@Test
public void testSpringContextBootstrappingInitializationUsingBasePackages() {
doSpringContextBootstrappingInitializationTest(
"cache-with-spring-context-bootstrap-initializer-using-base-packages.xml");
}
+ @Test
+ public void testSpringContextBootstrappingInitializationUsingContextConfigLocations() {
+ doSpringContextBootstrappingInitializationTest("cache-with-spring-context-bootstrap-initializer.xml");
+ }
+
public static final class TestDataSource extends DataSourceAdapter {
}
@@ -218,7 +224,7 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
private static final AtomicReference INSTANCE = new AtomicReference();
- private static final Map USER_DATA = new HashMap(3);
+ private static final Map USER_DATA = new ConcurrentHashMap(3);
static {
USER_DATA.put("jblum", new User("jblum"));
@@ -234,18 +240,19 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
}
protected static User createUser(final String username) {
- return createUser(username, String.format("%1$s@xcompay.com", username), true, Calendar.getInstance());
+ return createUser(username, true, Calendar.getInstance(), String.format("%1$s@xcompay.com", username));
}
protected static User createUser(final String username, final Boolean active) {
- return createUser(username, String.format("%1$s@xcompay.com", username), active, Calendar.getInstance());
+ 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) {
- return createUser(username, String.format("%1$s@xcompay.com", username), active, since);
+ return createUser(username, active, since, String.format("%1$s@xcompay.com", username));
}
- protected static User createUser(final String username, final String email, final Boolean active, final Calendar since) {
+ protected static User createUser(final String username, final Boolean active, final Calendar since,
+ final String email) {
User user = new User(username);
user.setActive(active);
user.setEmail(email);
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 88983d53..f17c7765 100644
--- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java
+++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java
@@ -20,9 +20,9 @@ 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.assertTrue;
-import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
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;
@@ -35,8 +35,10 @@ import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
-import org.springframework.util.ObjectUtils;
+import org.springframework.context.event.ContextStartedEvent;
+import org.springframework.context.event.ContextStoppedEvent;
/**
* The SpringContextBootstrappingInitializerTest class is a test suite of test cases testing the contract
@@ -69,143 +71,15 @@ public class SpringContextBootstrappingInitializerTest {
@After
public void tearDown() {
SpringContextBootstrappingInitializer.applicationContext = null;
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testCreateApplicationContextWhenBasePackagesAndConfigLocationsAreBothUnspecified() {
- try {
- new SpringContextBootstrappingInitializer().createApplicationContext(null, null);
- }
- catch (IllegalArgumentException expected) {
- assertEquals("Either 'basePackages' or 'configLocations' must be specified to construct 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 an instance of the ClassPathXmlApplicationContext.",
- expected.getMessage());
- throw expected;
- }
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testInitWithUnspecifiedBasePackagesAndContextConfigLocationsParameter() {
- try {
- new SpringContextBootstrappingInitializer().init(createParameters(createParameters(
- SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, ""),
- SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, ""));
- }
- catch (IllegalArgumentException expected) {
- assertEquals("Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.",
- expected.getMessage());
- throw expected;
- }
- }
-
- @Test(expected = IllegalStateException.class)
- public void testInitWithExistingApplicationContext() {
- try {
- ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
- "testInitWithExistingApplicationContext");
-
- when(mockApplicationContext.getId()).thenReturn("testInitWithExistingApplicationContext");
-
- SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext;
-
- new SpringContextBootstrappingInitializer().init(createParameters(
- SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
- "/path/to/spring/context/configuration/file.xml"));
- }
- catch (IllegalStateException expected) {
- assertEquals("A Spring application context with ID (testInitWithExistingApplicationContext) has already been created.",
- expected.getMessage());
- throw expected;
- }
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testInitWhenCreateApplicationContextReturnsNull() {
- try {
- SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
- @Override
- protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
- final String[] configLocations) {
- return null;
- }
- };
-
- initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
- "/path/to/spring/context/configuration/file.xml"));
- }
- catch (IllegalArgumentException expected) {
- assertEquals("The 'created' ConfigurableApplicationContext cannot be null!", expected.getMessage());
- throw expected;
- }
- }
-
- @Test(expected = IllegalStateException.class)
- public void testInitWithNonActiveApplicationContext() {
- final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
- "testInitWithNonActiveApplicationConstruct");
-
- when(mockApplicationContext.getId()).thenReturn("testInitWithNonActiveApplicationContext");
- when(mockApplicationContext.isActive()).thenReturn(false);
-
- SpringContextBootstrappingInitializer initializer = null;
-
- try {
- 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/context/configuration/file.xml"));
- }
- catch (IllegalStateException expected) {
- assertEquals("The Spring application context (testInitWithNonActiveApplicationContext) has failed to be properly initialized with the following config files ([/path/to/spring/context/configuration/file.xml]) or base packages ([])!",
- expected.getMessage());
- throw expected;
- }
- finally {
- verify(mockApplicationContext, times(1)).addApplicationListener(eq(initializer));
- verify(mockApplicationContext, times(1)).registerShutdownHook();
- verify(mockApplicationContext, times(1)).refresh();
- }
+ SpringContextBootstrappingInitializer.contextRefreshedEvent = null;
}
@Test
- public void testInitFollowedByGetApplicationContext() {
- final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
- "testInitFollowedByGetApplicationContext");
+ public void testGetApplicationContext() {
+ ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testGetApplicationContext");
- when(mockApplicationContext.getId()).thenReturn("testInitFollowedByGetApplicationContext");
- when(mockApplicationContext.isActive()).thenReturn(true);
-
- 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/context/configuration/file.xml"));
-
- verify(mockApplicationContext, times(1)).addApplicationListener(eq(initializer));
- verify(mockApplicationContext, times(1)).registerShutdownHook();
- verify(mockApplicationContext, times(1)).refresh();
+ SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext;
assertSame(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
}
@@ -216,7 +90,77 @@ public class SpringContextBootstrappingInitializerTest {
SpringContextBootstrappingInitializer.getApplicationContext();
}
catch (IllegalStateException expected) {
- assertEquals("The Spring ApplicationContext has not been created!", expected.getMessage());
+ assertEquals("The Spring ApplicationContext has not been properly configured and initialized!",
+ expected.getMessage());
+ throw expected;
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateApplicationContextWhenBothBasePackagesAndConfigLocationsAreUnspecified() {
+ 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());
+ throw expected;
+ }
+ }
+
+ @Test
+ public void testInitApplicationContext() {
+ ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testInitApplicationContext");
+
+ SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer();
+
+ initializer.initApplicationContext(mockApplicationContext);
+
+ verify(mockApplicationContext).addApplicationListener(same(initializer));
+ verify(mockApplicationContext).registerShutdownHook();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitApplicationContextWithNullContext() {
+ try {
+ new SpringContextBootstrappingInitializer().initApplicationContext(null);
+ }
+ catch (IllegalArgumentException expected) {
+ assertEquals("The ConfigurableApplicationContext reference must not be null!", expected.getMessage());
+ throw expected;
+ }
+ }
+
+ @Test
+ public void testRefreshApplicationContext() {
+ ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testInitApplicationContext");
+
+ new SpringContextBootstrappingInitializer().refreshApplicationContext(mockApplicationContext);
+
+ verify(mockApplicationContext).refresh();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testRefreshApplicationContextWithNullContext() {
+ try {
+ new SpringContextBootstrappingInitializer().refreshApplicationContext(null);
+ }
+ catch (IllegalArgumentException expected) {
+ assertEquals("The ConfigurableApplicationContext reference must not be null!", expected.getMessage());
throw expected;
}
}
@@ -238,97 +182,390 @@ public class SpringContextBootstrappingInitializerTest {
}
@Test
- public void testRegisterAndOnApplicationEvent() {
- TestApplicationListener testListener = SpringContextBootstrappingInitializer.register(
- new TestApplicationListener());
-
- try {
- ContextRefreshedEvent testEvent = new ContextRefreshedEvent(mock(ApplicationContext.class,
- "testRegisterAndOnApplicationEvent"));
-
- new SpringContextBootstrappingInitializer().onApplicationEvent(testEvent);
-
- testListener.assertCalled();
- testListener.assertSame(testEvent);
- }
- finally {
- SpringContextBootstrappingInitializer.unregister(testListener);
- }
- }
-
- @Test
- public void testRegisterUnregisterAndOnApplicationEvent() {
- TestApplicationListener testListener = SpringContextBootstrappingInitializer.unregister(
- SpringContextBootstrappingInitializer.register(new TestApplicationListener()));
-
- try {
- ContextRefreshedEvent testEvent = new ContextRefreshedEvent(mock(ApplicationContext.class,
- "testRegisterUnregisterAndOnApplicationEvent"));
-
- new SpringContextBootstrappingInitializer().onApplicationEvent(testEvent);
-
- testListener.assertNotCalled();
- }
- finally {
- SpringContextBootstrappingInitializer.unregister(testListener);
- }
- }
-
- @Test
- public void testNotifyListenersOnContextRefreshedEventBeforeApplicationContextExists() {
- TestApplicationListener testApplicationListener = new TestApplicationListener();
-
- SpringContextBootstrappingInitializer.applicationContext = null;
- SpringContextBootstrappingInitializer.register(testApplicationListener);
-
- testApplicationListener.assertNotCalled();
- }
-
- @Test
- public void testNotifyListenersOnContextRefreshedEventAfterApplicationContextRefreshed() {
+ public void testInitWithExistingApplicationContext() {
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
- "testNotifyListenersOnContextRefreshedEventAfterApplicationContextRefreshed");
+ "testInitWithExistingApplicationContext");
- ContextRefreshedEvent testEvent = new ContextRefreshedEvent(mockApplicationContext);
+ when(mockApplicationContext.isActive()).thenReturn(true);
+ when(mockApplicationContext.getId()).thenReturn("testInitWithExistingApplicationContext");
SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext;
- new SpringContextBootstrappingInitializer().onApplicationEvent(testEvent);
- TestApplicationListener testApplicationListener = new TestApplicationListener();
+ assertSame(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
- SpringContextBootstrappingInitializer.register(testApplicationListener);
+ SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer();
- testApplicationListener.assertCalled();
- testApplicationListener.assertSame(testEvent);
+ initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
+ "/path/to/spring/application/context.xml"));
+
+ verify(mockApplicationContext, never()).addApplicationListener(same(initializer));
+ verify(mockApplicationContext, never()).registerShutdownHook();
+ verify(mockApplicationContext, never()).refresh();
+
+ assertSame(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
}
- // TODO add additional multi-thread test cases once MultithreadedTC test framework is added to the SDP project
- // to properly test concurrency of the notification and registration during Spring ApplicationContext creation.
+ @Test
+ public void testInitWhenApplicationContextIsNull() {
+ assertNull(SpringContextBootstrappingInitializer.applicationContext);
+
+ final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testInitWhenApplicationContextIsNull");
+
+ when(mockApplicationContext.getId()).thenReturn("testInitWhenApplicationContextIsNull");
+ when(mockApplicationContext.isRunning()).thenReturn(true);
+
+ 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();
+
+ assertSame(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
+ }
+
+ @Test
+ public void testInitWhenApplicationContextIsInactive() {
+ ConfigurableApplicationContext mockInactiveApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testInitWhenApplicationContextIsInactive.Inactive");
+
+ when(mockInactiveApplicationContext.isActive()).thenReturn(false);
+
+ SpringContextBootstrappingInitializer.applicationContext = mockInactiveApplicationContext;
+
+ assertSame(mockInactiveApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
+
+ final ConfigurableApplicationContext mockNewApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testInitWhenApplicationContextIsInactive.New");
+
+ when(mockNewApplicationContext.getId()).thenReturn("testInitWhenApplicationContextIsInactive.New");
+ when(mockNewApplicationContext.isRunning()).thenReturn(true);
+
+ SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
+ @Override
+ protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
+ final String[] configLocations) {
+ return mockNewApplicationContext;
+ }
+ };
+
+ initializer.init(createParameters(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER,
+ "/path/to/spring/application/context.xml"));
+
+ verify(mockNewApplicationContext, times(1)).addApplicationListener(same(initializer));
+ verify(mockNewApplicationContext, times(1)).registerShutdownHook();
+ verify(mockNewApplicationContext, times(1)).refresh();
+
+ assertSame(mockNewApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInitWhenBothBasePackagesAndContextConfigLocationsParametersAreUnspecified() {
+ assertNull(SpringContextBootstrappingInitializer.applicationContext);
+
+ try {
+ new SpringContextBootstrappingInitializer().init(createParameters(createParameters(
+ SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, ""),
+ SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, ""));
+ }
+ catch (IllegalArgumentException expected) {
+ assertEquals("Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.",
+ expected.getMessage());
+ throw expected;
+ }
+ }
+
+ @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;
+ }
+ };
+
+ 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();
+
+ SpringContextBootstrappingInitializer.getApplicationContext();
+ }
+
+ protected static void assertNotifiedWithEvent(final TestApplicationListener listener, final ContextRefreshedEvent expectedEvent) {
+ Assert.assertTrue(listener.isNotified());
+ Assert.assertSame(expectedEvent, listener.getActualEvent());
+ }
+
+ protected static void assertUnnotified(final TestApplicationListener listener) {
+ assertFalse(listener.isNotified());
+ assertNull(listener.getActualEvent());
+ }
+
+ @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);
+
+ assertNotifiedWithEvent(testApplicationListener, testContextRefreshedEvent);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListener);
+ }
+ }
+
+ @Test
+ public void testOnApplicationEventWithContextStartedEvent() {
+ TestApplicationListener testApplicationListener = new TestApplicationListener(
+ "testOnApplicationEventWithContextStartedEvent");
+
+ try {
+ testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener);
+
+ assertUnnotified(testApplicationListener);
+
+ ContextStartedEvent testContextStartedEvent = mock(ContextStartedEvent.class,
+ "testOnApplicationEventWithContextStartedEvent");
+
+ new SpringContextBootstrappingInitializer().onApplicationEvent(testContextStartedEvent);
+
+ assertUnnotified(testApplicationListener);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListener);
+ }
+ }
+
+ @Test
+ public void testOnApplicationEventWithMultipleRegisteredApplicationListeners() {
+ TestApplicationListener testApplicationListenerOne = new TestApplicationListener(
+ "testOnApplicationEventWithMultipleRegisteredApplicationListeners.1");
+
+ TestApplicationListener testApplicationListenerTwo = new TestApplicationListener(
+ "testOnApplicationEventWithMultipleRegisteredApplicationListeners.2");
+
+ TestApplicationListener testApplicationListenerThree = new TestApplicationListener(
+ "testOnApplicationEventWithMultipleRegisteredApplicationListeners.3");
+
+ try {
+ testApplicationListenerOne = SpringContextBootstrappingInitializer.register(testApplicationListenerOne);
+ testApplicationListenerTwo = SpringContextBootstrappingInitializer.register(testApplicationListenerTwo);
+ testApplicationListenerThree = SpringContextBootstrappingInitializer.register(testApplicationListenerThree);
+
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+
+ ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class,
+ "testRegisterWithOnApplicationEvent"));
+
+ new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
+
+ assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
+ assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
+ assertNotifiedWithEvent(testApplicationListenerThree, testContextRefreshedEvent);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerOne);
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerTwo);
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerThree);
+ }
+ }
+
+ @Test
+ public void testOnApplicationEventWithUnregisteredApplicationListener() {
+ TestApplicationListener testApplicationListener = new TestApplicationListener(
+ "testOnApplicationEventWithUnregisteredApplicationListener");
+
+ try {
+ testApplicationListener = SpringContextBootstrappingInitializer.unregister(
+ SpringContextBootstrappingInitializer.register(testApplicationListener));
+
+ assertUnnotified(testApplicationListener);
+
+ ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class,
+ "testRegisterThenUnregisterWithOnApplicationEvent"));
+
+ new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
+
+ assertUnnotified(testApplicationListener);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListener);
+ }
+ }
+
+ @Test
+ public void testNotifyOnExistingContextRefreshedEventBeforeApplicationContextExists() {
+ assertNull(SpringContextBootstrappingInitializer.contextRefreshedEvent);
+
+ TestApplicationListener testApplicationListener = new TestApplicationListener(
+ "testNotifyOnExistingContextRefreshedEventBeforeApplicationContextExists");
+
+ try {
+ testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener);
+ assertUnnotified(testApplicationListener);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListener);
+ }
+ }
+
+ @Test
+ public void testNotifyOnExistingContextRefreshedEventAfterContextRefreshed() {
+ ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class));
+
+ new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent);
+
+ TestApplicationListener testApplicationListener = new TestApplicationListener(
+ "testNotifyApplicationListenersOnContextRefreshedEventAfterApplicationContextRefreshed");
+
+ try {
+ testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener);
+ assertNotifiedWithEvent(testApplicationListener, testContextRefreshedEvent);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListener);
+ }
+ }
+
+ @Test
+ public void testOnApplicationEventAndNotifyOnExistingContextRefreshedEvent() {
+ ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
+ "testOnApplicationEventAndNotifyOnExistingContextRefreshedEvent");
+
+ SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer();
+
+ TestApplicationListener testApplicationListenerOne = new TestApplicationListener(
+ "testOnApplicationEventAndNotifyOnExistingContextRefreshedEvent.1");
+
+ TestApplicationListener testApplicationListenerTwo = new TestApplicationListener(
+ "testOnApplicationEventAndNotifyOnExistingContextRefreshedEvent.2");
+
+ TestApplicationListener testApplicationListenerThree = new TestApplicationListener(
+ "testOnApplicationEventAndNotifyOnExistingContextRefreshedEvent.3");
+
+ try {
+ testApplicationListenerOne = SpringContextBootstrappingInitializer.register(testApplicationListenerOne);
+
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+
+ ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mockApplicationContext);
+
+ initializer.onApplicationEvent(testContextRefreshedEvent);
+
+ assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+
+ testApplicationListenerTwo = SpringContextBootstrappingInitializer.register(testApplicationListenerTwo);
+
+ assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerThree);
+
+ ContextStoppedEvent contextStoppedEvent = new ContextStoppedEvent(mockApplicationContext);
+
+ initializer.onApplicationEvent(contextStoppedEvent);
+
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+
+ initializer.onApplicationEvent(testContextRefreshedEvent);
+
+ assertNotifiedWithEvent(testApplicationListenerOne, testContextRefreshedEvent);
+ assertNotifiedWithEvent(testApplicationListenerTwo, testContextRefreshedEvent);
+ assertUnnotified(testApplicationListenerThree);
+
+ ContextClosedEvent testContextClosedEvent = new ContextClosedEvent(mockApplicationContext);
+
+ initializer.onApplicationEvent(testContextClosedEvent);
+
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+
+ SpringContextBootstrappingInitializer.register(testApplicationListenerThree);
+
+ assertUnnotified(testApplicationListenerOne);
+ assertUnnotified(testApplicationListenerTwo);
+ assertUnnotified(testApplicationListenerThree);
+ }
+ finally {
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerOne);
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerTwo);
+ SpringContextBootstrappingInitializer.unregister(testApplicationListenerThree);
+ }
+ }
+
+ // 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.
protected static class TestApplicationListener implements ApplicationListener {
- private volatile boolean called = false;
+ private volatile boolean notified = false;
private volatile ContextRefreshedEvent actualEvent;
- public void assertCalled() {
- assertTrue(String.format("Expected the (%1$s).onApplicationEvent(:ContextRefreshedEvent) method to be called!",
- getClass().getName()), called);
+ private final String name;
+
+ public TestApplicationListener(final String name) {
+ this.name = name;
}
- public void assertNotCalled() {
- assertFalse(String.format("Expected the (%1$s).onApplicationEvent(:ContextRefreshedEvent) method to not be called for ApplicationEvent (%2$s)!",
- getClass().getName(), ObjectUtils.nullSafeClassName(actualEvent)), called);
+ public ContextRefreshedEvent getActualEvent() {
+ ContextRefreshedEvent localActualEvent = this.actualEvent;
+ this.actualEvent = null;
+ return localActualEvent;
}
- public void assertSame(final ContextRefreshedEvent expectedEvent) {
- Assert.assertSame(expectedEvent, actualEvent);
+ public boolean isNotified() {
+ boolean localNotified = this.notified;
+ this.notified = false;
+ return localNotified;
}
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
this.actualEvent = event;
- called = true;
+ this.notified = true;
+ }
+
+ @Override
+ public String toString() {
+ return this.name;
}
}