SGF-400 - Enable the ability to set the ClassLoader used by the Spring ApplicationContext created in the SpringContextBootstrappingInitializer for loading bean definition classes and resolving resources.
This commit is contained in:
@@ -21,6 +21,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -35,6 +36,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.core.io.DefaultResourceLoader;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
@@ -71,6 +73,8 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
|
||||
private static final ApplicationEventMulticaster applicationEventNotifier = new SimpleApplicationEventMulticaster();
|
||||
|
||||
private static final AtomicReference<ClassLoader> beanClassLoaderRef = new AtomicReference<ClassLoader>(null);
|
||||
|
||||
/* package-private */ static volatile ConfigurableApplicationContext applicationContext;
|
||||
|
||||
/* package-private */ static volatile ContextRefreshedEvent contextRefreshedEvent;
|
||||
@@ -91,6 +95,24 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ClassLoader used by Spring ApplicationContext, created by this GemFire ("Bootstrapping") Initializer,
|
||||
* when creating bean definition classes.
|
||||
*
|
||||
* @param beanClassLoader the ClassLoader used by the Spring ApplicationContext to load bean definition classes.
|
||||
* @throws java.lang.IllegalStateException if the Spring ApplicationContext has already been created
|
||||
* and initialized.
|
||||
* @see java.lang.ClassLoader
|
||||
*/
|
||||
public static void setBeanClassLoader(ClassLoader beanClassLoader) {
|
||||
if (applicationContext == null || !applicationContext.isActive()) {
|
||||
beanClassLoaderRef.set(beanClassLoader);
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("The Spring ApplicationContext has already been initialized!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies any Spring ApplicationListeners of a current and existing ContextRefreshedEvent if the
|
||||
* ApplicationContext had been previously created, initialized and refreshed before any ApplicationListeners
|
||||
@@ -253,7 +275,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null!");
|
||||
applicationContext.addApplicationListener(this);
|
||||
applicationContext.registerShutdownHook();
|
||||
return applicationContext;
|
||||
return setClassLoader(applicationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,6 +350,24 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ClassLoader used to load bean definition classes on the Spring ApplicationContext.
|
||||
*
|
||||
* @param applicationContext the Spring ApplicationContext in which to configure the ClassLoader.
|
||||
* @return the given Spring ApplicationContext.
|
||||
* @see org.springframework.core.io.DefaultResourceLoader#setClassLoader(ClassLoader)
|
||||
* @see java.lang.ClassLoader
|
||||
*/
|
||||
ConfigurableApplicationContext setClassLoader(ConfigurableApplicationContext applicationContext) {
|
||||
ClassLoader beanClassLoader = beanClassLoaderRef.get();
|
||||
|
||||
if (applicationContext instanceof DefaultResourceLoader && beanClassLoader != null) {
|
||||
((DefaultResourceLoader) applicationContext).setClassLoader(beanClassLoader);
|
||||
}
|
||||
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a Spring ApplicationContext with the given parameters specified with a GemFire <initializer>
|
||||
* block in cache.xml.
|
||||
|
||||
@@ -51,6 +51,8 @@ import org.springframework.context.event.ContextClosedEvent;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.ContextStartedEvent;
|
||||
import org.springframework.context.event.ContextStoppedEvent;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* The SpringContextBootstrappingInitializerTest class is a test suite of test cases testing the contract
|
||||
@@ -70,6 +72,15 @@ import org.springframework.context.event.ContextStoppedEvent;
|
||||
@SuppressWarnings("unused")
|
||||
public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SpringContextBootstrappingInitializer.applicationContext = null;
|
||||
SpringContextBootstrappingInitializer.contextRefreshedEvent = null;
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(null);
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigOne.class);
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigTwo.class);
|
||||
}
|
||||
|
||||
protected static Properties createParameters(final String parameter, final String value) {
|
||||
Properties parameters = new Properties();
|
||||
parameters.setProperty(parameter, value);
|
||||
@@ -81,14 +92,6 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SpringContextBootstrappingInitializer.applicationContext = null;
|
||||
SpringContextBootstrappingInitializer.contextRefreshedEvent = null;
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigOne.class);
|
||||
SpringContextBootstrappingInitializer.unregister(TestAppConfigTwo.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetApplicationContext() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
@@ -111,6 +114,42 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBeanClassLoader() {
|
||||
assertNull(SpringContextBootstrappingInitializer.applicationContext);
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetBeanClassLoaderWhenApplicationContextIsInactive() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testSetBeanClassLoaderWhenApplicationContextIsInactive.MockApplicationContext");
|
||||
|
||||
when(mockApplicationContext.isActive()).thenReturn(false);
|
||||
|
||||
SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext;
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
verify(mockApplicationContext, times(1)).isActive();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSetBeanClassLoaderWhenApplicationContextIsActive() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testSetBeanClassLoaderWhenApplicationContextIsActive.MockApplicationContext");
|
||||
|
||||
when(mockApplicationContext.isActive()).thenReturn(true);
|
||||
|
||||
try {
|
||||
SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext;
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertEquals("The Spring ApplicationContext has already been initialized!", expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateApplicationContextWhenBasePackagesAndConfigLocationsAreUnspecified() {
|
||||
try {
|
||||
@@ -123,10 +162,57 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAnnotationApplicationContext() {
|
||||
final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testCreateAnnotationApplicationContext.MockXmlApplicationContext");
|
||||
|
||||
final AnnotationConfigApplicationContext mockAnnotationApplicationContext = mock(AnnotationConfigApplicationContext.class,
|
||||
"testCreateAnnotationApplicationContext.MockAnnotationApplicationContext");
|
||||
|
||||
String[] basePackages = { "org.example.app" };
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override ConfigurableApplicationContext createApplicationContext(final String[] configLocations) {
|
||||
return (ObjectUtils.isEmpty(configLocations) ? mockAnnotationApplicationContext
|
||||
: mockXmlApplicationContext);
|
||||
}
|
||||
};
|
||||
|
||||
ConfigurableApplicationContext actualApplicationContext = initializer.createApplicationContext(basePackages, null);
|
||||
|
||||
assertSame(mockAnnotationApplicationContext, actualApplicationContext);
|
||||
|
||||
verify(mockAnnotationApplicationContext, times(1)).scan(eq("org.example.app"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateXmlApplicationContext() {
|
||||
final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testCreateXmlApplicationContext.MockXmlApplicationContext");
|
||||
|
||||
final ConfigurableApplicationContext mockAnnotationApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testCreateXmlApplicationContext.MockAnnotationApplicationContext");
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override ConfigurableApplicationContext createApplicationContext(final String[] configLocations) {
|
||||
return (ObjectUtils.isEmpty(configLocations) ? mockAnnotationApplicationContext
|
||||
: mockXmlApplicationContext);
|
||||
}
|
||||
};
|
||||
|
||||
ConfigurableApplicationContext actualApplicationContext = initializer.createApplicationContext(null,
|
||||
new String[] { "/path/to/application/context.xml" });
|
||||
|
||||
assertSame(mockXmlApplicationContext, actualApplicationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitApplicationContext() {
|
||||
ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testInitApplicationContext");
|
||||
AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class,
|
||||
"testInitApplicationContext.MockApplicationContext");
|
||||
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer();
|
||||
|
||||
@@ -134,10 +220,11 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer));
|
||||
verify(mockApplicationContext, times(1)).registerShutdownHook();
|
||||
verify(mockApplicationContext, times(1)).setClassLoader(eq(Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInitApplicationContextWithNullContext() {
|
||||
public void testInitApplicationContextWithNull() {
|
||||
try {
|
||||
new SpringContextBootstrappingInitializer().initApplicationContext(null);
|
||||
}
|
||||
@@ -158,7 +245,7 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testRefreshApplicationContextWithNullContext() {
|
||||
public void testRefreshApplicationContextWithNull() {
|
||||
try {
|
||||
new SpringContextBootstrappingInitializer().refreshApplicationContext(null);
|
||||
}
|
||||
@@ -228,6 +315,30 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
verify(mockApplicationContext, never()).scan(any(String[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetClassLoader() {
|
||||
AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class,
|
||||
"testSetClassLoader.MockApplicationContext");
|
||||
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
|
||||
|
||||
new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext);
|
||||
|
||||
verify(mockApplicationContext, times(1)).setClassLoader(eq(Thread.currentThread().getContextClassLoader()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetClassLoaderWhenClassLoaderIsNull() {
|
||||
AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class,
|
||||
"testSetClassLoaderWhenClassLoaderIsNull.MockApplicationContext");
|
||||
|
||||
SpringContextBootstrappingInitializer.setBeanClassLoader(null);
|
||||
|
||||
new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext);
|
||||
|
||||
verify(mockApplicationContext, never()).setClassLoader(any(ClassLoader.class));
|
||||
}
|
||||
|
||||
private Class<?>[] annotatedClasses(final Class<?>... annotatedClasses) {
|
||||
return argThat(new ArgumentMatcher<Class<?>[]>() {
|
||||
@Override public boolean matches(final Object argument) {
|
||||
|
||||
Reference in New Issue
Block a user