/* * 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 static org.junit.Assert.fail; import java.util.Calendar; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import javax.sql.DataSource; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheClosedException; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.CacheLoader; import org.apache.geode.cache.CacheLoaderException; import org.apache.geode.cache.LoaderHelper; import org.apache.geode.cache.Region; 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.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.gemfire.config.xml.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.util.Assert; /** * The SpringContextBootstrappingInitializerTest class is a test suite of test cases testing the integrated * functionality of the SpringContextBootstrappingInitializer class. * * @author John Blum * @see org.junit.Test * @see org.springframework.context.ConfigurableApplicationContext * @see LazyWiringDeclarableSupport * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheFactory * @see org.apache.geode.cache.CacheLoader * @see org.apache.geode.cache.Region * @since 1.4.0 */ @SuppressWarnings("unused") public class SpringContextBootstrappingInitializerIntegrationTest { private static final long CACHE_CLOSE_TIMEOUT = TimeUnit.SECONDS.toMillis(15); private static final Object MUTEX_LOCK = new Object(); protected static final String GEMFIRE_LOCATORS = "localhost[11235]"; protected static final String GEMFIRE_LOG_LEVEL = "warning"; protected static final String GEMFIRE_JMX_MANAGER = "true"; protected static final String GEMFIRE_JMX_MANAGER_PORT = "1199"; protected static final String GEMFIRE_JMX_MANAGER_START = "true"; protected static final String GEMFIRE_MCAST_PORT = "0"; protected static final String GEMFIRE_NAME = SpringContextBootstrappingInitializerIntegrationTest.class.getSimpleName(); protected static final String GEMFIRE_START_LOCATORS = "localhost[11235]"; @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 in the allotted timeout of %1$d seconds!%n", (CACHE_CLOSE_TIMEOUT / 1000))); } catch (CacheClosedException ignore) { } } @After public void tearDown() { SpringContextBootstrappingInitializer.getApplicationContext().close(); 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("name", GEMFIRE_NAME) .set("mcast-port", GEMFIRE_MCAST_PORT) .set("log-level", GEMFIRE_LOG_LEVEL) .set("cache-xml-file", cacheXmlFile) //.set("locators", GEMFIRE_LOCATORS) //.set("start-locator", GEMFIRE_LOCATORS) //.set("jmx-manager", GEMFIRE_JMX_MANAGER) //.set("jmx-manager-port", GEMFIRE_JMX_MANAGER_PORT) //.set("jmx-manager-start", GEMFIRE_JMX_MANAGER_START) .create(); assertNotNull("The GemFire Cache was not properly created and initialized!", gemfireCache); assertFalse("The GemFire Cache is closed!", 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(); 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()); } @Test public void testSpringContextBootstrappingInitializerUsingAnnotatedClasses() { SpringContextBootstrappingInitializer.register(TestAppConfig.class); new SpringContextBootstrappingInitializer().init(new Properties()); ConfigurableApplicationContext applicationContext = SpringContextBootstrappingInitializer.getApplicationContext(); UserDataStoreCacheLoader userDataStoreCacheLoader = applicationContext.getBean(UserDataStoreCacheLoader.class); DataSource userDataSource = applicationContext.getBean(DataSource.class); assertSame(UserDataStoreCacheLoader.getInstance(), userDataStoreCacheLoader); assertSame(userDataStoreCacheLoader.getDataSource(), userDataSource); } @Test public void testSpringContextBootstrappingInitializerUsingBasePackages() { doSpringContextBootstrappingInitializationTest( "cache-with-spring-context-bootstrap-initializer-using-base-packages.xml"); } @Test public void testSpringContextBootstrappingInitializerUsingContextConfigLocations() { doSpringContextBootstrappingInitializationTest("cache-with-spring-context-bootstrap-initializer.xml"); } @Configuration public static class TestAppConfig { @Bean public DataSource userDataSource() { return new TestDataSource(); } @Bean public UserDataStoreCacheLoader userDataStoreCacheLoader() { return new UserDataStoreCacheLoader(); } } public static final class TestDataSource extends DataSourceAdapter { } 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 ConcurrentHashMap<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; protected static User createUser(String username) { return createUser(username, true, Calendar.getInstance(), String.format("%1$s@xcompay.com", username)); } protected static User createUser(String username, Boolean active) { return createUser(username, active, Calendar.getInstance(), String.format("%1$s@xcompay.com", username)); } protected static User createUser(String username, Boolean active, Calendar since) { return createUser(username, active, since, String.format("%1$s@xcompay.com", username)); } protected static User createUser(String username, Boolean active, Calendar since, String email) { User user = new User(username); user.setActive(active); user.setEmail(email); user.setSince(since); return user; } public static UserDataStoreCacheLoader getInstance() { return INSTANCE.get(); } public UserDataStoreCacheLoader() { Assert.state(INSTANCE.compareAndSet(null, this), String.format("An instance of %1$s was already created!", getClass().getName())); } @Override protected void assertInitialized() { super.assertInitialized(); Assert.state(userDataSource != null, String.format( "The 'User' Data Source was not properly configured and initialized for use in (%1$s!)", getClass().getName())); } protected DataSource getDataSource() { return userDataSource; } @Override public void close() { userDataSource = null; } @Override public User load(final LoaderHelper<String, User> helper) throws CacheLoaderException { assertInitialized(); return USER_DATA.get(helper.getKey()); } } }