Early solution for SGF-248 concerning bootstrapping a Spring ApplicationContext inside a GemFire Server-based JVM process when starting the GemFire Server from Gfsh.
This commit is contained in:
@@ -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.
|
||||
* <p/>
|
||||
* @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<ContextRefreshedEvent>, Declarable {
|
||||
|
||||
// The name of the template bean defined in the Spring context for wiring this Declarable instance.
|
||||
private static final String BEAN_NAME_PARAMETER = "bean-name";
|
||||
|
||||
// atomic reference to the parameter passed by GemFire when this Declared was constructed
|
||||
// and the init method was called.
|
||||
private final AtomicReference<Properties> parametersReference = new AtomicReference<Properties>();
|
||||
|
||||
private volatile boolean initialized = false;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @param beanFactory the ConfigurableListableBeanFactory used to configure and initialize this Declarable GemFire
|
||||
* component.
|
||||
* @param parameters Properties instance containing the parameters from GemFire's configuration file
|
||||
* (e.g. cache.xml) to configure this Declarable object.
|
||||
* @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>.
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
* <p/>
|
||||
* @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<ContextRefreshedEvent> {
|
||||
|
||||
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.
|
||||
* <p/>
|
||||
* @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).
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @param applicationContext the Spring ApplicationContext to retrieve the ID of.
|
||||
* @return the ID of the given Spring ApplicationContext or null if the ApplicationContext reference is null.
|
||||
* @see org.springframework.context.ApplicationContext#getId()
|
||||
*/
|
||||
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).
|
||||
* <p/>
|
||||
* @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.
|
||||
* <p/>
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
* <p/>
|
||||
* @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<Region<?, ?>> 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<String, User> 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<String, User> {
|
||||
|
||||
private static final AtomicReference<UserDataStoreCacheLoader> INSTANCE = new AtomicReference<UserDataStoreCacheLoader>();
|
||||
|
||||
private static final Map<String, User> USER_DATA = new HashMap<String, User>(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<String, User> helper) throws CacheLoaderException {
|
||||
assertInitialized();
|
||||
return USER_DATA.get(helper.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
* <p/>
|
||||
* @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> T unwrap(final Class<T> iface) throws SQLException {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_EXCEPTION_MESSAGE);
|
||||
}
|
||||
|
||||
}
|
||||
22
src/test/resources/cache-with-initializer.xml
Normal file
22
src/test/resources/cache-with-initializer.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE cache PUBLIC "-//GemStone Systems, Inc.//GemFire Declarative Caching 7.0//EN"
|
||||
"http://www.gemstone.com/dtd/cache7_0.dtd">
|
||||
<cache>
|
||||
<region name="Users" refid="REPLICATE">
|
||||
<region-attributes initial-capacity="101" load-factor="0.85">
|
||||
<cache-loader>
|
||||
<class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerTest$UserDataStoreCacheLoader</class-name>
|
||||
</cache-loader>
|
||||
</region-attributes>
|
||||
</region>
|
||||
<initializer>
|
||||
<class-name>org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer</class-name>
|
||||
<parameter name="contextConfigLocations">
|
||||
<string>
|
||||
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
|
||||
</string>
|
||||
</parameter>
|
||||
</initializer>
|
||||
</cache>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
">
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean id="userDataSource" class="org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerTest$TestDataSource"/>
|
||||
<bean id="userDao" class="org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerTest$TestUserDao"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:gfe="http://www.springframework.org/schema/gemfire"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
|
||||
">
|
||||
|
||||
<gfe:cache/>
|
||||
<gfe:replicated-region id="TestRegion" persistent="false"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
">
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<bean name="userService" class="org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerTest$TestUserService"/>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user