Completed all testing and interface/functional changes for SGF-248 - Bootstrapping a Spring ApplicationContext with GemFire.

This commit is contained in:
John Blum
2014-01-27 18:45:53 -08:00
parent 5476837119
commit ba84061b48
9 changed files with 705 additions and 28 deletions

View File

@@ -40,6 +40,8 @@ import com.gemstone.gemfire.cache.Declarable;
* @author John Blum
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.data.gemfire.DeclarableSupport
* @see org.springframework.data.gemfire.WiringDeclarableSupport
* @see com.gemstone.gemfire.cache.Declarable
* @since 1.3.4
*/
@@ -47,19 +49,19 @@ import com.gemstone.gemfire.cache.Declarable;
public abstract class LazyWiringDeclarableSupport implements ApplicationListener<ContextRefreshedEvent>, Declarable {
// The name of the template bean defined in the Spring context for wiring this Declarable instance.
private static final String BEAN_NAME_PARAMETER = "bean-name";
protected static final String BEAN_NAME_PARAMETER = "bean-name";
// atomic reference to the parameter passed by GemFire when this Declared was constructed
// and the init method was called.
private final AtomicReference<Properties> parametersReference = new AtomicReference<Properties>();
private volatile boolean initialized = false;
protected volatile boolean initialized = false;
/**
* Constructs an instance of the LazyWiringDeclarableSupport class register with the
* Constructs an instance of the LazyWiringDeclarableSupport class registered with the
* SpringContextBootstrappingInitializer to receive notification when the Spring context is created and initialized
* by GemFire to that this Declarable component can be configured and properly initialized with any required Spring
* bean dependencies.
* (refreshed) by GemFire in order for this Declarable component to be configured and properly initialized with any
* required Spring bean dependencies.
* <p/>
* @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer
* #register(org.springframework.context.ApplicationListener)
@@ -70,12 +72,13 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener
/**
* Asserts that this Declarable object has been properly configured and initialized by the Spring container
* after GemFire has constructed this Declarable during startup. It is recommended that this method be called
* in any GemFire CacheCallback/Declarable object operational method (e.g. CacheLoader.load(..)) before use
* in order to ensure that this Declarable was properly constructed, configured and initialized.
* after GemFire has constructed this Declarable object during startup. It is recommended that this method
* be called in any GemFire CacheCallback/Declarable object operational method (e.g. CacheLoader.load(..))
* before use in order to ensure that this Declarable was properly constructed, configured and initialized.
* <p/>
* @throws IllegalStateException if the Declarable object has not been properly configured or initialized by the
* Spring container.
* @throws IllegalStateException if the Declarable object has not been properly configured or initialized
* by the Spring container.
* @see #init(java.util.Properties)
* @see #isInitialized()
*/
protected void assertInitialized() {
@@ -86,19 +89,21 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener
/**
* Performs the actual configuration and initialization of this Declarable object before use. This method
* is triggered by an ApplicationEvent indicating that the Spring context has been created and refreshed.
* is triggered by an ApplicationEvent (specifically, the ContextRefreshedEvent) indicating that the Spring context
* has been created and refreshed.
* <p/>
* @param beanFactory the ConfigurableListableBeanFactory used to configure and initialize this Declarable GemFire
* component.
* @param parameters Properties instance containing the parameters from GemFire's configuration file
* (e.g. cache.xml) to configure this Declarable object.
* (e.g. cache.xml) to configure and initialize this Declarable object.
* @throws IllegalArgumentException if the bean-name parameter was specified in GemFire configuration meta-data
* but no bean with the specified name could be found in the Spring context.
* @see #init(java.util.Properties)
* @see org.springframework.beans.factory.wiring.BeanConfigurerSupport
* @see org.springframework.beans.factory.wiring.BeanWiringInfo
* @see org.springframework.beans.factory.wiring.BeanWiringInfoResolver
*/
protected void doInit(final ConfigurableListableBeanFactory beanFactory, final Properties parameters) {
/* package-private */ void doInit(final ConfigurableListableBeanFactory beanFactory, final Properties parameters) {
BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport();
beanConfigurer.setBeanFactory(beanFactory);
@@ -124,11 +129,24 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener
beanConfigurer.destroy();
initialized = true;
doPostInit(parameters);
}
/**
* Default no operation method performed post initialization of this Declarable GemFire component to be overridden
* by subclasses for application specific extension and behavior.
* <p/>
* @param parameters Properties instance containing the parameters from GemFire's configuration file
* (e.g. cache.xml) to configure and initialize this Declarable object.
* @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties)
*/
protected void doPostInit(final Properties parameters) {
}
/**
* Initialization method called by GemFire with the configured parameters once this Declarable object has been
* constructed during GemFire startup using an &lt;initalizer&gt;.
* constructed during GemFire startup using an &lt;initalizer&gt; element in GemFire's configuration meta-data.
* <p/>
* @param parameters the configured parameters passed from the GemFire configuration (e.g. cache.xml) to this
* Declarable as a Properties instance.
@@ -148,6 +166,7 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener
* <p/>
* @return a boolean value indicating whether this Declarable object has been configured and initialized by
* the Spring container.
* @see #assertInitialized()
* @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties)
*/
protected boolean isInitialized() {
@@ -164,6 +183,9 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener
* called this Declarable object's init method yet, which is probably a bug and violates the lifecycle contract
* of Declarable GemFire objects).
* @throws IllegalArgumentException if the ApplicationContext is not an instance of ConfigurableApplicationContext.
* @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties)
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
* @see org.springframework.context.event.ContextRefreshedEvent
*/
@Override
public final void onApplicationEvent(final ContextRefreshedEvent event) {

View File

@@ -39,6 +39,11 @@ import com.gemstone.gemfire.cache.Declarable;
* and initializes the Cache for use.
* <p/>
* @author John Blum
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ApplicationEventMulticaster
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.support.ClassPathXmlApplicationContext
* @see com.gemstone.gemfire.cache.Declarable
@@ -50,7 +55,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
public static final String CONTEXT_CONFIG_LOCATIONS_PARAMETER = "contextConfigLocations";
private static ConfigurableApplicationContext applicationContext;
/* package-private */ static ConfigurableApplicationContext applicationContext;
// TODO consider whether I should register a TaskExecutor to perform the event notifications in a separate Thread???
private static ApplicationEventMulticaster eventNotifier = new SimpleApplicationEventMulticaster();
@@ -72,25 +77,51 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
* when instantiating and initializing declared Initializers from the GemFire native configuration file
* (e.g. cache.xml).
* <p/>
* @param listener the ApplicationListener to register for ContextStartedEvents by this
* @param <T> the Class type of the Spring ApplicationListener.
* @param listener the ApplicationListener to register for ContextRefreshedEvents by this
* SpringContextBootstrappingInitializer.
* @return the reference to the ApplicationListener for method call chaining purposes.
* @see #unregister(org.springframework.context.ApplicationListener)
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
* #addApplicationListener(org.springframework.context.ApplicationListener)
*/
public static void register(ApplicationListener listener) {
public static <T extends ApplicationListener> T register(final T listener) {
eventNotifier.addApplicationListener(listener);
return listener;
}
/**
* Gets the the ID of the Spring ApplicationContext in a null-safe manner.
* Unregisters the Spring ApplicationListener from this SpringContextBootstrappingInitializer in order to stop
* receiving ApplicationEvents on Spring context refreshes.
* <p/>
* @param applicationContext the Spring ApplicationContext to retrieve the ID of.
* @return the ID of the given Spring ApplicationContext or null if the ApplicationContext reference is null.
* @see org.springframework.context.ApplicationContext#getId()
* @param <T> the Class type of the Spring ApplicationListener.
* @param listener the ApplicationListener to unregister from receiving ContextRefreshedEvents by this
* SpringContextBootstrappingInitializer.
* @return the reference to the ApplicationListener for method call chaining purposes.
* @see #register(org.springframework.context.ApplicationListener)
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.SimpleApplicationEventMulticaster
* #removeApplicationListener(org.springframework.context.ApplicationListener)
*/
protected static String nullSafeGetApplicationContextId(final ApplicationContext applicationContext) {
return (applicationContext != null ? applicationContext.getId() : null);
public static <T extends ApplicationListener> T unregister(final T listener) {
eventNotifier.removeApplicationListener(listener);
return listener;
}
/**
* Creates (constructs and initializes) a ConfigurableApplicationContext instance based on the specified locations
* of the context configuration meta-data files and indicates whether ApplicationContext.refresh should happen
* automatically during creation. This method allows subclasses to override the type of
* ConfigurableApplicationContext created; by default, a ClassPathXmlApplicationContext is created.
* <p/>
* @param configLocations a String array indicating the locations of the context configuration meta-data files.
* @param refresh a boolean value indicating whether the ApplicationContext is refreshed on creation.
* @return a newly constructed and initialized instance of a ConfigurableApplicationContext.
* @see org.springframework.context.support.ClassPathXmlApplicationContext
*/
protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations, final boolean refresh) {
return new ClassPathXmlApplicationContext(configLocations, refresh);
}
/**
@@ -99,6 +130,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
* <p/>
* @param parameters a Properties object containing the configuration parameters and settings defined in the
* GemFire cache.xml &gt;initializer/&lt; element.
* @see #createApplicationContext(String[], boolean)
* @see java.util.Properties
*/
@Override
@@ -116,17 +148,28 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
"A Spring application context with ID (%1$s) has already been created.",
nullSafeGetApplicationContextId(applicationContext)));
applicationContext = new ClassPathXmlApplicationContext(configLocations, false);
applicationContext = createApplicationContext(configLocations, false);
applicationContext.addApplicationListener(this);
applicationContext.registerShutdownHook();
applicationContext.refresh();
Assert.state(applicationContext.isActive(), String.format(
"The Spring application context has failed to be properly initialized with the following config files (%1$s)!",
Arrays.toString(configLocations)));
"The Spring application context (%1$s) has failed to be properly initialized with the following config files (%2$s)!",
nullSafeGetApplicationContextId(applicationContext), Arrays.toString(configLocations)));
}
}
/**
* Gets the the ID of the Spring ApplicationContext in a null-safe manner.
* <p/>
* @param applicationContext the Spring ApplicationContext to retrieve the ID for.
* @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) {
return (applicationContext != null ? applicationContext.getId() : null);
}
/**
* 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