Added support to the SpringContextBootstrappingInitializer class for component scanning given a set of base packages to scan. Refactored LazyWiringDeclarableSupport to implement the DisposableBean interface in order for any extending bean component to unregister itself from the SpringContextBootstrappingInitializer to stop receiving ApplicationContext event notifications when destroyed. Fully tested the application component scanning and configuration using Annotations and JavaConfig-based configuration, uplifting some of the application components (UserDao, UserService, etc) from the integration test and adding a UserApplicationConfiguration @Configuration component in order to test this functionlity properly.
This commit is contained in:
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
@@ -29,18 +30,21 @@ import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.data.gemfire.LazyWiringDeclarableSupport;
|
||||
import org.springframework.data.gemfire.config.GemfireConstants;
|
||||
import org.springframework.data.gemfire.repository.sample.User;
|
||||
import org.springframework.data.gemfire.support.sample.TestUserDao;
|
||||
import org.springframework.data.gemfire.support.sample.TestUserService;
|
||||
import org.springframework.data.gemfire.test.support.DataSourceAdapter;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.CacheClosedException;
|
||||
import com.gemstone.gemfire.cache.CacheFactory;
|
||||
import com.gemstone.gemfire.cache.CacheLoader;
|
||||
import com.gemstone.gemfire.cache.CacheLoaderException;
|
||||
@@ -53,28 +57,101 @@ import com.gemstone.gemfire.cache.Region;
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.data.gemfire.LazyWiringDeclarableSupport
|
||||
* @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer
|
||||
* @see com.gemstone.gemfire.cache.Cache
|
||||
* @see com.gemstone.gemfire.cache.CacheFactory
|
||||
* @see com.gemstone.gemfire.cache.CacheLoader
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.3.4 (Spring Data GemFire)
|
||||
* @since 7.0.1 (GemFire)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
|
||||
private static final long CACHE_CLOSE_TIMEOUT = 15000l; // 15 seconds
|
||||
|
||||
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_MCAST_PORT = "0";
|
||||
protected static final String GEMFIRE_NAME = "SpringContextBootstrappingInitializationTest";
|
||||
protected static final String GEMFIRE_START_LOCATORS = "localhost[11235]";
|
||||
|
||||
@Test
|
||||
public void testSpringContextBootstrappingInitialization() {
|
||||
@Before
|
||||
public void setup() {
|
||||
setupBeforeCacheCreate();
|
||||
}
|
||||
|
||||
private void setupBeforeCacheCreate() {
|
||||
try {
|
||||
long timeout = (System.currentTimeMillis() + CACHE_CLOSE_TIMEOUT);
|
||||
|
||||
while (CacheFactory.getAnyInstance() != null && System.currentTimeMillis() < timeout) {
|
||||
synchronized (MUTEX_LOCK) {
|
||||
try {
|
||||
System.out.printf("Waiting in setup...%n");
|
||||
MUTEX_LOCK.wait(500l);
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fail(String.format("The Cache instance was not properly closed and shutdown by the timeout of %1$d seconds!%n",
|
||||
(CACHE_CLOSE_TIMEOUT / 1000)));
|
||||
}
|
||||
catch (CacheClosedException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SpringContextBootstrappingInitializer.applicationContext = null;
|
||||
UserDataStoreCacheLoader.INSTANCE.set(null);
|
||||
tearDownCache();
|
||||
}
|
||||
|
||||
private void tearDownCache() {
|
||||
try {
|
||||
Cache cache = CacheFactory.getAnyInstance();
|
||||
|
||||
if (cache != null) {
|
||||
System.out.printf("Closing Cache...%n");
|
||||
cache.close();
|
||||
|
||||
// Now, wait for the GemFire Hog to shutdown, OIY!
|
||||
synchronized (MUTEX_LOCK) {
|
||||
while (!cache.isClosed()) {
|
||||
try {
|
||||
System.out.printf("Waiting in tearDown...");
|
||||
MUTEX_LOCK.wait(500l);
|
||||
}
|
||||
catch (InterruptedException ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_LOCK.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CacheClosedException ignore) {
|
||||
// CacheClosedExceptions happen when the Cache reference returned by GemFireCacheImpl.getInstance()
|
||||
// inside the CacheFactory.getAnyInstance() is null, or the Cache is already closed with calling
|
||||
// Cache.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void doSpringContextBootstrappingInitializationTest(final String cacheXmlFile) {
|
||||
Cache gemfireCache = new CacheFactory()
|
||||
.set("cache-xml-file", "cache-with-spring-context-bootstrap-initializer.xml")
|
||||
.set("locators", GEMFIRE_LOCATORS)
|
||||
.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("start-locator", GEMFIRE_LOCATORS)
|
||||
.create();
|
||||
|
||||
assertNotNull("The GemFire Cache was not properly created or initialized!", gemfireCache);
|
||||
@@ -124,39 +201,20 @@ 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");
|
||||
}
|
||||
|
||||
public static final class TestDataSource extends DataSourceAdapter {
|
||||
}
|
||||
|
||||
@Repository
|
||||
public static interface UserDao {
|
||||
}
|
||||
|
||||
public static final class TestUserDao implements UserDao {
|
||||
|
||||
@Autowired
|
||||
private DataSource userDataSource;
|
||||
|
||||
protected DataSource getDataSource() {
|
||||
Assert.state(userDataSource != null, "A reference to the Users DataSource as not properly configured!");
|
||||
return userDataSource;
|
||||
}
|
||||
}
|
||||
|
||||
@Service
|
||||
public static interface UserService {
|
||||
}
|
||||
|
||||
public static final class TestUserService implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
protected UserDao getUserDao() {
|
||||
Assert.state(userDao != null, "A reference to the UserDao was not properly configured!");
|
||||
return userDao;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class UserDataStoreCacheLoader extends LazyWiringDeclarableSupport implements CacheLoader<String, User> {
|
||||
|
||||
private static final AtomicReference<UserDataStoreCacheLoader> INSTANCE = new AtomicReference<UserDataStoreCacheLoader>();
|
||||
@@ -207,7 +265,6 @@ public class SpringContextBootstrappingInitializerIntegrationTest {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
USER_DATA.clear();
|
||||
userDataSource = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,30 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
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("The configLocations must be specified to construct an instance of the ClassPathXmlApplicationContext.",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testInitWithUnspecifiedContextConfigLocationsParameter() {
|
||||
try {
|
||||
@@ -71,7 +95,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, ""));
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("The contextConfigLocations parameter is required.", expected.getMessage());
|
||||
assertEquals("Either 'basePackages' or the 'contextConfigLocations' parameter must be specified.",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
@@ -98,11 +123,11 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testInitWithNonActiveApplicationConstruct() {
|
||||
public void testInitWithNonActiveApplicationContext() {
|
||||
final ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class,
|
||||
"testInitWithNonActiveApplicationConstruct");
|
||||
|
||||
when(mockApplicationContext.getId()).thenReturn("testInitWithNonActiveApplicationConstruct");
|
||||
when(mockApplicationContext.getId()).thenReturn("testInitWithNonActiveApplicationContext");
|
||||
when(mockApplicationContext.isActive()).thenReturn(false);
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = null;
|
||||
@@ -110,7 +135,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
try {
|
||||
initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations, final boolean refresh) {
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
final String[] configLocations) {
|
||||
return mockApplicationContext;
|
||||
}
|
||||
};
|
||||
@@ -119,7 +145,7 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
"/path/to/spring/context/configuration/file.xml"));
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertEquals("The Spring application context (testInitWithNonActiveApplicationConstruct) has failed to be properly initialized with the following config files ([/path/to/spring/context/configuration/file.xml])!",
|
||||
assertEquals("The Spring application context (testInitWithNonActiveApplicationContext) has failed to be properly initialized with the following config files ([/path/to/spring/context/configuration/file.xml])!",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
@@ -140,7 +166,8 @@ public class SpringContextBootstrappingInitializerTest {
|
||||
|
||||
SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() {
|
||||
@Override
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations, final boolean refresh) {
|
||||
protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages,
|
||||
final String[] configLocations) {
|
||||
return mockApplicationContext;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support.sample;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The TestUserDao class is an implementation of the UserDao Data Access Object (DAO) interface for performing
|
||||
* data access and persistence operations on Users.
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.sample.User
|
||||
* @see org.springframework.data.gemfire.support.sample.UserDao
|
||||
* @see org.springframework.stereotype.Repository
|
||||
* @since 1.3.4
|
||||
*/
|
||||
@Repository("userDao")
|
||||
@SuppressWarnings("unused")
|
||||
public class TestUserDao implements UserDao {
|
||||
|
||||
@Autowired
|
||||
private DataSource userDataSource;
|
||||
|
||||
public DataSource getDataSource() {
|
||||
Assert.state(userDataSource != null, "A reference to the Users DataSource was not properly configured!");
|
||||
return userDataSource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support.sample;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The TestUserService class is an implementation of the UserService service interface for performing service operations
|
||||
* on Users.
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.sample.User
|
||||
* @see org.springframework.data.gemfire.support.sample.UserService
|
||||
* @see org.springframework.stereotype.Service
|
||||
* @since 1.3.4
|
||||
*/
|
||||
@Service("userService")
|
||||
@SuppressWarnings("unused")
|
||||
public class TestUserService implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserDao userDao;
|
||||
|
||||
public UserDao getUserDao() {
|
||||
Assert.state(userDao != null, "A reference to the UserDao was not properly configured!");
|
||||
return userDao;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support.sample;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest;
|
||||
|
||||
/**
|
||||
* The UserApplicationConfiguration class is a configuration component for confguring the user's application.
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.ImportResource
|
||||
* @since 1.3.4
|
||||
*/
|
||||
@Configuration
|
||||
@ImportResource({ "classpath:org/springframework/data/gemfire/support/sample/initializer-gemfire-context.xml" })
|
||||
@SuppressWarnings("unused")
|
||||
public class UserApplicationConfiguration {
|
||||
|
||||
@Bean
|
||||
public DataSource userDataSource() {
|
||||
return new SpringContextBootstrappingInitializerIntegrationTest.TestDataSource();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support.sample;
|
||||
|
||||
/**
|
||||
* The UserDao interface is a contract for implementing objects containing data access functionality for Users.
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.sample.User
|
||||
* @since 1.3.4
|
||||
*/
|
||||
public interface UserDao {
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.support.sample;
|
||||
|
||||
/**
|
||||
* The UserService interface is a contract for implementing objects to service Users.
|
||||
* <p/>
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.repository.sample.User
|
||||
* @since 1.3.4
|
||||
*/
|
||||
public interface UserService {
|
||||
}
|
||||
Reference in New Issue
Block a user