From f6ccc09c2345d48b858d46ca3343d8a213cf3c6c Mon Sep 17 00:00:00 2001 From: John Blum Date: Fri, 7 Feb 2014 18:25:31 -0800 Subject: [PATCH] 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. --- .../gemfire/LazyWiringDeclarableSupport.java | 18 ++- ...SpringContextBootstrappingInitializer.java | 87 +++++++++--- ...otstrappingInitializerIntegrationTest.java | 133 +++++++++++++----- ...ngContextBootstrappingInitializerTest.java | 39 ++++- .../gemfire/support/sample/TestUserDao.java | 46 ++++++ .../support/sample/TestUserService.java | 44 ++++++ .../sample/UserApplicationConfiguration.java | 45 ++++++ .../data/gemfire/support/sample/UserDao.java | 27 ++++ .../gemfire/support/sample/UserService.java | 27 ++++ ...tstrap-initializer-using-base-packages.xml | 22 +++ ...h-spring-context-bootstrap-initializer.xml | 6 +- .../{ => sample}/initializer-dao-context.xml | 2 +- .../initializer-gemfire-context.xml | 3 +- .../initializer-services-context.xml | 2 +- 14 files changed, 434 insertions(+), 67 deletions(-) create mode 100644 src/test/java/org/springframework/data/gemfire/support/sample/TestUserDao.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/sample/TestUserService.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/sample/UserApplicationConfiguration.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/sample/UserDao.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/sample/UserService.java create mode 100644 src/test/resources/cache-with-spring-context-bootstrap-initializer-using-base-packages.xml rename src/test/resources/org/springframework/data/gemfire/support/{ => sample}/initializer-dao-context.xml (91%) rename src/test/resources/org/springframework/data/gemfire/support/{ => sample}/initializer-gemfire-context.xml (81%) rename src/test/resources/org/springframework/data/gemfire/support/{ => sample}/initializer-services-context.xml (87%) diff --git a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java index 51988441..50a72ed4 100644 --- a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java +++ b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java @@ -19,6 +19,7 @@ package org.springframework.data.gemfire; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; +import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.wiring.BeanConfigurerSupport; import org.springframework.beans.factory.wiring.BeanWiringInfo; @@ -38,6 +39,7 @@ import com.gemstone.gemfire.cache.Declarable; * for wiring GemFire components with Spring bean dependencies defined in the Spring context. *

* @author John Blum + * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.context.ApplicationListener * @see org.springframework.context.event.ContextRefreshedEvent * @see org.springframework.data.gemfire.DeclarableSupport @@ -46,7 +48,8 @@ import com.gemstone.gemfire.cache.Declarable; * @since 1.3.4 */ @SuppressWarnings("unused") -public abstract class LazyWiringDeclarableSupport implements ApplicationListener, Declarable { +public abstract class LazyWiringDeclarableSupport implements ApplicationListener, + Declarable, DisposableBean { // The name of the template bean defined in the Spring context for wiring this Declarable instance. protected static final String BEAN_NAME_PARAMETER = "bean-name"; @@ -201,4 +204,17 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener doInit(((ConfigurableApplicationContext) event.getApplicationContext()).getBeanFactory(), parameters); } + /** + * When this bean gets destroyed by the Spring container, make sure this component gets unregistered from the + * SpringContextBootstrappingInitializer. + *

+ * @throws Exception if bean destruction is unsuccessful. + * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer#unregister( + * org.springframework.context.ApplicationListener) + */ + @Override + public void destroy() throws Exception { + SpringContextBootstrappingInitializer.unregister(this); + } + } 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 6e4cd9dd..1fb8b571 100644 --- a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java +++ b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java @@ -22,11 +22,13 @@ import java.util.Properties; 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.ApplicationEventMulticaster; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import com.gemstone.gemfire.cache.Declarable; @@ -41,21 +43,27 @@ import com.gemstone.gemfire.cache.Declarable; * @author John Blum * @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.ConfigurableApplicationContext * @see org.springframework.context.support.ClassPathXmlApplicationContext * @see com.gemstone.gemfire.cache.Declarable * @since 1.3.4 * @link http://pubs.vmware.com/vfabric53/topic/com.vmware.vfabric.gemfire.7.0/basic_config/the_cache/setting_cache_initializer.html + * @link https://jira.springsource.org/browse/SGF-248 */ @SuppressWarnings("unused") public class SpringContextBootstrappingInitializer implements Declarable, ApplicationListener { + public static final String BASE_PACKAGES_PARAMETER = "basePackages"; public static final String CONTEXT_CONFIG_LOCATIONS_PARAMETER = "contextConfigLocations"; - /* package-private */ static ConfigurableApplicationContext applicationContext; + protected static final String CHARS_TO_DELETE = " \n\t"; + protected static final String COMMA_DELIMITER = ","; + + /* 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 ApplicationEventMulticaster eventNotifier = new SimpleApplicationEventMulticaster(); @@ -110,18 +118,61 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic } /** - * 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. + * Creates (constructs and configures) a ConfigurableApplicationContext instance based on the specified locations + * of the context configuration meta-data files. The created ConfigurableApplicationContext is not automatically + * "refreshed" and therefore must be "refreshed" by the caller manually. *

- * @param configLocations a String array indicating the locations of the context configuration meta-data files. - * @param refresh a boolean value indicating whether the ApplicationContext is refreshed on creation. - * @return a newly constructed and initialized instance of a ConfigurableApplicationContext. + * @param configLocations a String array indicating the locations of the context configuration meta-data files + * used to configure the ConfigurableApplicationContext instance. + * @return a newly constructed and configured instance of the ConfigurableApplicationContext class. Note, the + * "refresh" method must be called manually before using the context. + * @throws IllegalArgumentException if the configLocations parameter argument is null or empty. + * @see #createApplicationContext(String[], String[]) * @see org.springframework.context.support.ClassPathXmlApplicationContext */ - protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations, final boolean refresh) { - return new ClassPathXmlApplicationContext(configLocations, refresh); + protected ConfigurableApplicationContext createApplicationContext(final String[] configLocations) { + Assert.notEmpty(configLocations, "The configLocations must be specified to construct 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. + *

+ * 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. + *

+ * @param basePackages the base application 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. + * @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. + * @throws IllegalArgumentException if both the basePackages and configLocation parameter arguments + * are null or empty. + * @see #createApplicationContext(String[]) + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext#scan(String...) + * @see org.springframework.context.support.ClassPathXmlApplicationContext + */ + protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages, + final String[] configLocations) { + if (!ObjectUtils.isEmpty(configLocations)) { + return new ClassPathXmlApplicationContext(configLocations, false); + } + else { + Assert.notEmpty(basePackages, "Either 'basePackages' or 'configLocations' must be specified" + + " to construct an instance of the ConfigurableApplicationContext."); + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + applicationContext.scan(basePackages); + return applicationContext; + } } /** @@ -130,25 +181,29 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic *

* @param parameters a Properties object containing the configuration parameters and settings defined in the * GemFire cache.xml >initializer/< element. - * @see #createApplicationContext(String[], boolean) + * @see #createApplicationContext * @see java.util.Properties */ @Override public void init(final Properties parameters) { + String basePackages = parameters.getProperty(BASE_PACKAGES_PARAMETER); String contextConfigLocations = parameters.getProperty(CONTEXT_CONFIG_LOCATIONS_PARAMETER); - Assert.hasText(contextConfigLocations, "The contextConfigLocations parameter is required."); + Assert.isTrue(StringUtils.hasText(basePackages) || StringUtils.hasText(contextConfigLocations), + "Either 'basePackages' or the 'contextConfigLocations' parameter must be specified."); - String[] configLocations = contextConfigLocations.split(","); + String[] basePackagesArray = StringUtils.delimitedListToStringArray(basePackages, + COMMA_DELIMITER, CHARS_TO_DELETE); - StringUtils.trimArrayElements(configLocations); + 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(configLocations, false); + applicationContext = createApplicationContext(basePackagesArray, configLocations); applicationContext.addApplicationListener(this); applicationContext.registerShutdownHook(); applicationContext.refresh(); 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 ab926a3d..a76cf30e 100644 --- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java @@ -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; *

* @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 { private static final AtomicReference INSTANCE = new AtomicReference(); @@ -207,7 +265,6 @@ public class SpringContextBootstrappingInitializerIntegrationTest { @Override public void close() { - USER_DATA.clear(); userDataSource = null; } 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 3fec4ba1..5e236b7b 100644 --- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java @@ -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; } }; diff --git a/src/test/java/org/springframework/data/gemfire/support/sample/TestUserDao.java b/src/test/java/org/springframework/data/gemfire/support/sample/TestUserDao.java new file mode 100644 index 00000000..febdfc51 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/sample/TestUserDao.java @@ -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. + *

+ * @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; + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/sample/TestUserService.java b/src/test/java/org/springframework/data/gemfire/support/sample/TestUserService.java new file mode 100644 index 00000000..899e39f1 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/sample/TestUserService.java @@ -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. + *

+ * @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; + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/sample/UserApplicationConfiguration.java b/src/test/java/org/springframework/data/gemfire/support/sample/UserApplicationConfiguration.java new file mode 100644 index 00000000..ccb7945f --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/sample/UserApplicationConfiguration.java @@ -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. + *

+ * @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(); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/support/sample/UserDao.java b/src/test/java/org/springframework/data/gemfire/support/sample/UserDao.java new file mode 100644 index 00000000..8664b58f --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/sample/UserDao.java @@ -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. + *

+ * @author John Blum + * @see org.springframework.data.gemfire.repository.sample.User + * @since 1.3.4 + */ +public interface UserDao { +} diff --git a/src/test/java/org/springframework/data/gemfire/support/sample/UserService.java b/src/test/java/org/springframework/data/gemfire/support/sample/UserService.java new file mode 100644 index 00000000..0a08dcbf --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/sample/UserService.java @@ -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. + *

+ * @author John Blum + * @see org.springframework.data.gemfire.repository.sample.User + * @since 1.3.4 + */ +public interface UserService { +} diff --git a/src/test/resources/cache-with-spring-context-bootstrap-initializer-using-base-packages.xml b/src/test/resources/cache-with-spring-context-bootstrap-initializer-using-base-packages.xml new file mode 100644 index 00000000..cdfc177e --- /dev/null +++ b/src/test/resources/cache-with-spring-context-bootstrap-initializer-using-base-packages.xml @@ -0,0 +1,22 @@ + + + + + + java.lang.String + org.springframework.data.gemfire.repository.sample.User + + org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest$UserDataStoreCacheLoader + + + + + org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + + + org.springframework.data.gemfire.support.sample + + + + diff --git a/src/test/resources/cache-with-spring-context-bootstrap-initializer.xml b/src/test/resources/cache-with-spring-context-bootstrap-initializer.xml index d73a5305..ad5baec0 100644 --- a/src/test/resources/cache-with-spring-context-bootstrap-initializer.xml +++ b/src/test/resources/cache-with-spring-context-bootstrap-initializer.xml @@ -15,9 +15,9 @@ org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer - classpath:org/springframework/data/gemfire/support/initializer-gemfire-context.xml, - classpath:org/springframework/data/gemfire/support/initializer-dao-context.xml, - classpath:org/springframework/data/gemfire/support/initializer-services-context.xml + classpath:org/springframework/data/gemfire/support/sample/initializer-gemfire-context.xml, + classpath:org/springframework/data/gemfire/support/sample/initializer-dao-context.xml, + classpath:org/springframework/data/gemfire/support/sample/initializer-services-context.xml diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-dao-context.xml similarity index 91% rename from src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml rename to src/test/resources/org/springframework/data/gemfire/support/sample/initializer-dao-context.xml index 66396e57..4bad00d3 100644 --- a/src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-dao-context.xml @@ -10,6 +10,6 @@ - + diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-gemfire-context.xml similarity index 81% rename from src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml rename to src/test/resources/org/springframework/data/gemfire/support/sample/initializer-gemfire-context.xml index 1e652bdc..52c5e8d3 100644 --- a/src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-gemfire-context.xml @@ -1,4 +1,5 @@ + - + diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-services-context.xml similarity index 87% rename from src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml rename to src/test/resources/org/springframework/data/gemfire/support/sample/initializer-services-context.xml index 7a4c8caf..2c0c64ec 100644 --- a/src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/sample/initializer-services-context.xml @@ -9,6 +9,6 @@ - +