From 8e57cc05a373930cccc83ccae5b594bb0e389a08 Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 23 Jan 2014 19:30:16 -0800 Subject: [PATCH] Early solution for SGF-248 concerning bootstrapping a Spring ApplicationContext inside a GemFire Server-based JVM process when starting the GemFire Server from Gfsh. --- .../gemfire/LazyWiringDeclarableSupport.java | 182 +++++++++++++++ ...SpringContextBootstrappingInitializer.java | 146 ++++++++++++ ...ngContextBootstrappingInitializerTest.java | 215 ++++++++++++++++++ .../test/support/DataSourceAdapter.java | 76 +++++++ src/test/resources/cache-with-initializer.xml | 22 ++ .../support/initializer-dao-context.xml | 15 ++ .../support/initializer-gemfire-context.xml | 13 ++ .../support/initializer-services-context.xml | 14 ++ 8 files changed, 683 insertions(+) create mode 100644 src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java create mode 100644 src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java create mode 100644 src/test/java/org/springframework/data/gemfire/test/support/DataSourceAdapter.java create mode 100644 src/test/resources/cache-with-initializer.xml create mode 100644 src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml create mode 100644 src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml create mode 100644 src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml diff --git a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java new file mode 100644 index 00000000..edee9d90 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java @@ -0,0 +1,182 @@ +/* + * 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; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.wiring.BeanConfigurerSupport; +import org.springframework.beans.factory.wiring.BeanWiringInfo; +import org.springframework.beans.factory.wiring.BeanWiringInfoResolver; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import com.gemstone.gemfire.cache.Declarable; + +/** + * The LazyWiringDeclarableSupport class is an implementation of the GemFire Declarable interface that enables support + * for wiring GemFire components with Spring bean dependencies defined in the Spring context. + *

+ * @author John Blum + * @see org.springframework.context.ApplicationListener + * @see org.springframework.context.event.ContextRefreshedEvent + * @see com.gemstone.gemfire.cache.Declarable + * @since 1.3.4 + */ +@SuppressWarnings("unused") +public abstract class LazyWiringDeclarableSupport implements ApplicationListener, 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"; + + // atomic reference to the parameter passed by GemFire when this Declared was constructed + // and the init method was called. + private final AtomicReference parametersReference = new AtomicReference(); + + private volatile boolean initialized = false; + + /** + * Constructs an instance of the LazyWiringDeclarableSupport class register 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. + *

+ * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + * #register(org.springframework.context.ApplicationListener) + */ + public LazyWiringDeclarableSupport() { + SpringContextBootstrappingInitializer.register(this); + } + + /** + * 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. + *

+ * @throws IllegalStateException if the Declarable object has not been properly configured or initialized by the + * Spring container. + * @see #isInitialized() + */ + protected void assertInitialized() { + Assert.state(isInitialized(), String.format( + "This Declarable object (%1$s) has not ben properly configured and initialized!", + getClass().getName())); + } + + /** + * 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. + *

+ * @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. + * @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 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) { + BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); + + beanConfigurer.setBeanFactory(beanFactory); + + final String templateBeanName = parameters.getProperty(BEAN_NAME_PARAMETER); + + if (StringUtils.hasText(templateBeanName)) { + if (beanFactory.containsBean(templateBeanName)) { + beanConfigurer.setBeanWiringInfoResolver(new BeanWiringInfoResolver() { + @Override public BeanWiringInfo resolveWiringInfo(final Object beanInstance) { + return new BeanWiringInfo(templateBeanName); + } + }); + } + else { + throw new IllegalArgumentException(String.format( + "No bean with name '%1$s' was found in the Spring context '%2$s'.", templateBeanName, beanFactory)); + } + } + + beanConfigurer.afterPropertiesSet(); + beanConfigurer.configureBean(this); + beanConfigurer.destroy(); + + initialized = true; + } + + /** + * Initialization method called by GemFire with the configured parameters once this Declarable object has been + * constructed during GemFire startup using an <initalizer>. + *

+ * @param parameters the configured parameters passed from the GemFire configuration (e.g. cache.xml) to this + * Declarable as a Properties instance. + * @throws IllegalStateException if the Declarable object's init method has already been invoked. + * @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + * @see java.util.Properties + */ + @Override + public final void init(final Properties parameters) { + Assert.state(parametersReference.compareAndSet(null, parameters), String.format( + "This Declarable (%1$s) has already been initialized.", getClass().getName())); + } + + /** + * Determines whether this Declarable object has been configured and initialized (i.e. the doInit method + * has been called) by the Spring container. + *

+ * @return a boolean value indicating whether this Declarable object has been configured and initialized by + * the Spring container. + * @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + */ + protected boolean isInitialized() { + return initialized; + } + + /** + * Event handler method called when GemFire has created and initialized (refreshed) the Spring ApplicationContext + * using the SpringContextBootstrappingInitializer Declarable class. + *

+ * @param event the ContextRefreshedEvent published by the Spring ApplicationContext after it is successfully + * created and initialized by GemFire. + * @throws IllegalStateException if the parameters have not been passed to this Declarable (i.e. GemFire has not + * 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. + */ + @Override + public final void onApplicationEvent(final ContextRefreshedEvent event) { + Properties parameters = parametersReference.get(); + + Assert.state(parameters != null, String.format( + "This Declarable object's (%1$s) init method has not been invoked!", getClass().getName())); + + Assert.isTrue(event.getApplicationContext() instanceof ConfigurableApplicationContext, + String.format("The Spring ApplicationContext (%1$s) must be an instance of ConfigurableApplicationContext.", + ObjectUtils.nullSafeClassName(event.getApplicationContext()))); + + doInit(((ConfigurableApplicationContext) event.getApplicationContext()).getBeanFactory(), parameters); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java new file mode 100644 index 00000000..06f84316 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java @@ -0,0 +1,146 @@ +/* + * 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; + +import java.util.Arrays; +import java.util.Properties; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +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.StringUtils; + +import com.gemstone.gemfire.cache.Declarable; + +/** + * The SpringContextBootstrappingInitializer class is a GemFire configuration initializer used to bootstrap a Spring + * ApplicationContext inside a GemFire Server JVM-based process. This enables a GemFire Cache Server resources to be + * mostly configured with Spring Data GemFire's XML namespace. The Cache itself is the only resource that cannot be + * configured and initialized in a Spring context since the initializer is not invoked until after GemFire creates + * and initializes the Cache for use. + *

+ * @author John Blum + * @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 + */ +@SuppressWarnings("unused") +public class SpringContextBootstrappingInitializer implements Declarable, ApplicationListener { + + public static final String CONTEXT_CONFIG_LOCATIONS_PARAMETER = "contextConfigLocations"; + + 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(); + + /** + * Gets a reference to the Spring ApplicationContext constructed, configured and initialized inside the GemFire + * Server-based JVM process. + *

+ * @return a reference to the Spring ApplicationContext bootstrapped by GemFire. + * @see org.springframework.context.ConfigurableApplicationContext + */ + public static synchronized ConfigurableApplicationContext getApplicationContext() { + Assert.state(applicationContext != null, "The Spring ApplicationContext has not been created!"); + return applicationContext; + } + + /** + * 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). + *

+ * @param listener the ApplicationListener to register for ContextStartedEvents by this + * SpringContextBootstrappingInitializer. + * @see org.springframework.context.ApplicationListener + * @see org.springframework.context.event.SimpleApplicationEventMulticaster + * #addApplicationListener(org.springframework.context.ApplicationListener) + */ + public static void register(ApplicationListener listener) { + eventNotifier.addApplicationListener(listener); + } + + /** + * Gets the the ID of the Spring ApplicationContext in a null-safe manner. + *

+ * @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() + */ + protected static String nullSafeGetApplicationContextId(final ApplicationContext applicationContext) { + return (applicationContext != null ? applicationContext.getId() : null); + } + + /** + * Initializes a Spring ApplicationContext with the given parameters from a GemFire Initializer in GemFire native + * configuration meta-data (e.g. cache.xml). + *

+ * @param parameters a Properties object containing the configuration parameters and settings defined in the + * GemFire cache.xml >initializer/< element. + * @see java.util.Properties + */ + @Override + public void init(final Properties parameters) { + String contextConfigLocations = parameters.getProperty(CONTEXT_CONFIG_LOCATIONS_PARAMETER); + + Assert.hasText(contextConfigLocations, "The contextConfigLocations parameter is required."); + + String[] configLocations = contextConfigLocations.split(","); + + StringUtils.trimArrayElements(configLocations); + + synchronized (SpringContextBootstrappingInitializer.class) { + Assert.state(applicationContext == null, String.format( + "A Spring application context with ID (%1$s) has already been created.", + nullSafeGetApplicationContextId(applicationContext))); + + applicationContext = new ClassPathXmlApplicationContext(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))); + } + } + + /** + * 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. + *

+ * @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) + */ + @Override + public void onApplicationEvent(final ContextRefreshedEvent event) { + eventNotifier.multicastEvent(event); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java new file mode 100644 index 00000000..90ea96ba --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java @@ -0,0 +1,215 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +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 java.util.Calendar; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import javax.sql.DataSource; + +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.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.CacheFactory; +import com.gemstone.gemfire.cache.CacheLoader; +import com.gemstone.gemfire.cache.CacheLoaderException; +import com.gemstone.gemfire.cache.LoaderHelper; +import com.gemstone.gemfire.cache.Region; + +/** + * The SpringContextBootstrappingInitializerTest class is a test suite of test cases testing the functionality of the + * SpringContextBootstrappingInitializer class + *

+ * @author John Blum + * @see org.junit.Test + * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + * @since 1.3.4 (Spring Data GemFire) + * @since 7.0.1 (GemFire) + */ +@SuppressWarnings("unused") +public class SpringContextBootstrappingInitializerTest { + + 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() { + Cache gemfireCache = new CacheFactory() + .set("cache-xml-file", "cache-with-initializer.xml") + .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) + .create(); + + assertNotNull("The GemFire Cache was not properly created or initialized!", gemfireCache); + assertFalse("The GemFire Cache is close!", gemfireCache.isClosed()); + + Set> rootRegions = gemfireCache.rootRegions(); + + assertNotNull(rootRegions); + assertFalse(rootRegions.isEmpty()); + assertEquals(2, rootRegions.size()); + assertNotNull(gemfireCache.getRegion("/TestRegion")); + assertNotNull(gemfireCache.getRegion("/Users")); + + ConfigurableApplicationContext applicationContext = SpringContextBootstrappingInitializer.getApplicationContext(); + + assertNotNull(applicationContext); + assertTrue(applicationContext.containsBean(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)); + assertTrue(applicationContext.containsBean("TestRegion")); + assertFalse(applicationContext.containsBean("Users")); // Region 'Users' is defined in GemFire cache.xml + assertTrue(applicationContext.containsBean("userDataSource")); + assertTrue(applicationContext.containsBean("userDao")); + assertTrue(applicationContext.containsBean("userService")); + + DataSource userDataSource = applicationContext.getBean("userDataSource", DataSource.class); + TestUserDao userDao = applicationContext.getBean("userDao", TestUserDao.class); + TestUserService userService = applicationContext.getBean("userService", TestUserService.class); + + assertSame(userDataSource, userDao.getDataSource()); + assertSame(userDao, userService.getUserDao()); + + // NOTE a GemFire declared component initialized by Spring! + UserDataStoreCacheLoader usersCacheLoader = UserDataStoreCacheLoader.getInstance(); + + assertNotNull(usersCacheLoader); + assertSame(userDataSource, usersCacheLoader.getDataSource()); + + Region users = gemfireCache.getRegion("/Users"); + + assertNotNull(users); + assertEquals("Users", users.getName()); + assertEquals("/Users", users.getFullPath()); + assertTrue(users.isEmpty()); + assertEquals(UserDataStoreCacheLoader.USER_DATA.get("jblum"), users.get("jblum")); + assertEquals(UserDataStoreCacheLoader.USER_DATA.get("jdoe"), users.get("jdoe")); + assertEquals(UserDataStoreCacheLoader.USER_DATA.get("jhandy"), users.get("jhandy")); + assertFalse(users.isEmpty()); + assertEquals(3, users.size()); + } + + 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() { + return userDataSource; + } + } + + @Service + public static interface UserService { + } + + public static final class TestUserService implements UserService { + + @Autowired + private UserDao userDao; + + protected UserDao getUserDao() { + return userDao; + } + } + + public static final class UserDataStoreCacheLoader extends LazyWiringDeclarableSupport implements CacheLoader { + + private static final AtomicReference INSTANCE = new AtomicReference(); + + private static final Map USER_DATA = new HashMap(3); + + static { + USER_DATA.put("jblum", new User("jblum")); + USER_DATA.put("jdoe", new User("jdoe")); + USER_DATA.put("jhandy", new User("jhandy")); + } + + @Autowired + private DataSource userDataSource; + + public static UserDataStoreCacheLoader getInstance() { + return INSTANCE.get(); + } + + protected static User createUser(final String username) { + return createUser(username, String.format("%1$s@xcompay.com", username), true, Calendar.getInstance()); + } + + protected static User createUser(final String username, final Boolean active) { + return createUser(username, String.format("%1$s@xcompay.com", username), active, Calendar.getInstance()); + } + + protected static User createUser(final String username, final String email, final Boolean active, final Calendar since) { + User user = new User(username); + user.setActive(active); + user.setEmail(email); + user.setSince(since); + return user; + } + + public UserDataStoreCacheLoader() { + Assert.state(INSTANCE.compareAndSet(null, this), String.format("An instance of %1$s was already created!", + getClass().getName())); + } + + protected DataSource getDataSource() { + return userDataSource; + } + + @Override + public void close() { + USER_DATA.clear(); + userDataSource = null; + } + + @Override + public User load(final LoaderHelper helper) throws CacheLoaderException { + assertInitialized(); + return USER_DATA.get(helper.getKey()); + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/test/support/DataSourceAdapter.java b/src/test/java/org/springframework/data/gemfire/test/support/DataSourceAdapter.java new file mode 100644 index 00000000..132302cb --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/test/support/DataSourceAdapter.java @@ -0,0 +1,76 @@ +/* + * 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.test.support; + +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; + +/** + * The DataSourceAdapter class is an implementation of the DataSource interface with unsupported operations by default. + *

+ * @author John Blum + * @see javax.sql.DataSource + * @since 1.3.4 + */ +@SuppressWarnings("unused") +public abstract class DataSourceAdapter implements DataSource { + + private static final String UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE = "Not Implemented"; + + @Override + public Connection getConnection() throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public Connection getConnection(final String username, final String password) throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public void setLogWriter(final PrintWriter out) throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public int getLoginTimeout() throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public void setLoginTimeout(final int seconds) throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public boolean isWrapperFor(final Class iface) throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + + @Override + public T unwrap(final Class iface) throws SQLException { + throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE); + } + +} diff --git a/src/test/resources/cache-with-initializer.xml b/src/test/resources/cache-with-initializer.xml new file mode 100644 index 00000000..89246298 --- /dev/null +++ b/src/test/resources/cache-with-initializer.xml @@ -0,0 +1,22 @@ + + + + + + + org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerTest$UserDataStoreCacheLoader + + + + + 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 + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml b/src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml new file mode 100644 index 00000000..41fed417 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/support/initializer-dao-context.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml b/src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml new file mode 100644 index 00000000..1e652bdc --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/support/initializer-gemfire-context.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml b/src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml new file mode 100644 index 00000000..c759db37 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/support/initializer-services-context.xml @@ -0,0 +1,14 @@ + + + + + + + +