From b02abf2c1e3a8d5e08abca4a8522dd623b4b4e60 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 29 Feb 2016 18:08:19 -0800 Subject: [PATCH] SGF-476 - Implement ServerLauncherCacheProvider to launch Geode with Spring. Geode has removed the direct dependency on spring data gemfire in favor of using a ServiceLoader to allow overriding the behavior of geode's server launcher start behavior. Implementing the ServerLauncherCacheProvider interface to allow SDG to override the server launcher behavior to parse a spring xml file, if present. (cherry picked from commit 4272216552d3404922a50c8cba7492b9893d1f8d) Signed-off-by: John Blum --- .../SpringServerLauncherCacheProvider.java | 81 ++++++++++++++++ ...re.distributed.ServerLauncherCacheProvider | 1 + ...rLauncherCacheProviderIntegrationTest.java | 93 +++++++++++++++++++ ...SpringServerLauncherCacheProviderTest.java | 92 ++++++++++++++++++ ...erCacheProviderIntegrationTest-context.xml | 25 +++++ 5 files changed, 292 insertions(+) create mode 100644 src/main/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProvider.java create mode 100644 src/main/resources/META-INF/services/com.gemstone.gemfire.distributed.ServerLauncherCacheProvider create mode 100644 src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderIntegrationTest.java create mode 100644 src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderTest.java create mode 100644 src/test/resources/SpringServerLauncherCacheProviderIntegrationTest-context.xml diff --git a/src/main/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProvider.java b/src/main/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProvider.java new file mode 100644 index 00000000..687f6a32 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016 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.Collections; +import java.util.Properties; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.distributed.ServerLauncher; +import com.gemstone.gemfire.distributed.ServerLauncher.Builder; +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.internal.util.CollectionUtils; +import com.gemstone.gemfire.distributed.ServerLauncherCacheProvider; + +/** + * The SpringServerLauncherCacheProvider class is overrides the default behavior + * of GemFire's ServerLauncher to bootstrap the cache using a Spring + * ApplicationContext instead of a GemFire cache.xml inside a GemFire Server + * JVM-based process. This enables a GemFire Cache Server resources to be + * configured with Spring Data GemFire's XML namespace. + * + * Unlike {@link SpringContextBootstrappingInitializer}, this allows the configuration + * of the cache to specified in the Spring Context. + * + * To use this cache provider, ensure that the spring data gemfire jars are on + * the classpath of the GemFire server and specify the --spring-xml-location + * option from the command line or call {@link Builder#setSpringXmlLocation(String)} + * when launching the GemFire server. + * + * @author Dan Smith + * @see ServerLauncherCacheProvider + * @see SpringContextBootstrappingInitializer + * @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.ApplicationContextEvent + * @see org.springframework.context.event.ApplicationEventMulticaster + * @see org.springframework.context.support.ClassPathXmlApplicationContext + * @see com.gemstone.gemfire.cache.Declarable + * @link http://gemfire.docs.pivotal.io/latest/userguide/index.html#basic_config + * /the_cache/setting_cache_initializer.html + */ +public class SpringServerLauncherCacheProvider implements ServerLauncherCacheProvider { + + @Override + public Cache createCache(Properties gemfireProperties, ServerLauncher serverLauncher) { + if (!serverLauncher.isSpringXmlLocationSpecified()) { + return null; + } + + System.setProperty(DistributionConfig.GEMFIRE_PREFIX + DistributionConfig.NAME_NAME, + serverLauncher.getMemberName()); + + createSpringContextBootstrappingInitializer().init(CollectionUtils.createProperties( + Collections.singletonMap(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, + serverLauncher.getSpringXmlLocation()))); + + return SpringContextBootstrappingInitializer.getApplicationContext().getBean(Cache.class); + } + + /* Used for testing purposes */ + protected SpringContextBootstrappingInitializer createSpringContextBootstrappingInitializer() { + return new SpringContextBootstrappingInitializer(); + } + +} diff --git a/src/main/resources/META-INF/services/com.gemstone.gemfire.distributed.ServerLauncherCacheProvider b/src/main/resources/META-INF/services/com.gemstone.gemfire.distributed.ServerLauncherCacheProvider new file mode 100644 index 00000000..160f734f --- /dev/null +++ b/src/main/resources/META-INF/services/com.gemstone.gemfire.distributed.ServerLauncherCacheProvider @@ -0,0 +1 @@ +org.springframework.data.gemfire.support.SpringServerLauncherCacheProvider \ No newline at end of file diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderIntegrationTest.java new file mode 100644 index 00000000..0505ed15 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderIntegrationTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016 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.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; + +import org.junit.After; +import org.junit.Test; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializerIntegrationTest.UserDataStoreCacheLoader; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheClosedException; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.distributed.AbstractLauncher.Status; +import com.gemstone.gemfire.distributed.ServerLauncher; +import com.gemstone.gemfire.distributed.ServerLauncher.ServerState; +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.internal.util.CollectionUtils; + +/** + * The SpringServerLauncherCacheProviderTest class is a test suite of test cases testing the contract and functionality + * of the SpringServerLauncherCacheProvider class. This test class focuses on testing isolated units of functionality in + * the ServerLauncherCacheProvider class directly, mocking any dependencies as appropriate, in order for the class to + * uphold it's contract. + * + * @author Dan Smith + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.context.ApplicationContext + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.data.gemfire.support.SpringServerLauncherCacheProvider + */ +public class SpringServerLauncherCacheProviderIntegrationTest { + + @After + public void tearDown() { + System.clearProperty(DistributionConfig.GEMFIRE_PREFIX + DistributionConfig.NAME_NAME); + SpringContextBootstrappingInitializer.getApplicationContext().close(); + tearDownCache(); + } + + private void tearDownCache() { + try { + Cache cache = CacheFactory.getAnyInstance(); + + if (cache != null) { + cache.close(); + } + } + 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(); + } + } + + @Test + public void createCacheWithSpecifiedConfig() { + String xmlLocation = getClass().getSimpleName() + "-context.xml"; + + ServerLauncher launcher = mock(ServerLauncher.class); + + ServerLauncher.Builder builder = new ServerLauncher.Builder(); + builder.setSpringXmlLocation(xmlLocation); + builder.setMemberName("membername"); + launcher = builder.build(); + ServerState state = launcher.start(); + assertEquals(Status.ONLINE, state.getStatus()); + ConfigurableApplicationContext ctx = SpringContextBootstrappingInitializer.getApplicationContext(); + Cache cache = ctx.getBean(Cache.class); + assertNotNull(cache); + assertEquals(55, cache.getResourceManager().getCriticalHeapPercentage(), 0.1); + assertEquals(Status.STOPPED, launcher.stop().getStatus()); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderTest.java new file mode 100644 index 00000000..3a53c3b7 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/SpringServerLauncherCacheProviderTest.java @@ -0,0 +1,92 @@ +/* + * Copyright 2016 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.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; + +import org.junit.After; +import org.junit.Test; +import org.springframework.context.ConfigurableApplicationContext; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.distributed.ServerLauncher; +import com.gemstone.gemfire.distributed.internal.DistributionConfig; +import com.gemstone.gemfire.internal.util.CollectionUtils; + +/** + * The SpringServerLauncherCacheProviderTest class is a test suite of test cases testing the contract and functionality + * of the SpringServerLauncherCacheProvider class. This test class focuses on testing isolated units of functionality in + * the ServerLauncherCacheProvider class directly, mocking any dependencies as appropriate, in order for the class to + * uphold it's contract. + * + * @author Dan Smith + * @see org.junit.Test + * @see org.mockito.Mockito + * @see org.springframework.context.ApplicationContext + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.data.gemfire.support.SpringServerLauncherCacheProvider + */ +public class SpringServerLauncherCacheProviderTest { + + @After + public void tearDown() { + System.clearProperty(DistributionConfig.GEMFIRE_PREFIX + DistributionConfig.NAME_NAME); + SpringContextBootstrappingInitializer.applicationContext = null; + } + + @Test + public void doesNothingWhenSpringXmlLocationNotSpecified() { + SpringServerLauncherCacheProvider provider = new SpringServerLauncherCacheProvider(); + ServerLauncher launcher = mock(ServerLauncher.class); + when(launcher.isSpringXmlLocationSpecified()).thenReturn(false); + assertEquals(null, provider.createCache(null, launcher)); + verify(launcher).isSpringXmlLocationSpecified(); + } + + @Test + public void createCacheWithSpecifiedConfig() { + String xmlLocation = "xml/location"; + + ServerLauncher launcher = mock(ServerLauncher.class); + when(launcher.isSpringXmlLocationSpecified()).thenReturn(true); + when(launcher.getSpringXmlLocation()).thenReturn(xmlLocation); + when(launcher.getMemberName()).thenReturn("membername"); + + final SpringContextBootstrappingInitializer initializer = mock(SpringContextBootstrappingInitializer.class); + ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class); + SpringContextBootstrappingInitializer.applicationContext = context; + Cache cache = mock(Cache.class); + when(context.getBean(eq(Cache.class))).thenReturn(cache ); + + SpringServerLauncherCacheProvider provider = new SpringServerLauncherCacheProvider() { + @Override + public SpringContextBootstrappingInitializer createSpringContextBootstrappingInitializer() { + return initializer; + } + }; + + assertEquals(cache, provider.createCache(null, launcher)); + verify(launcher).isSpringXmlLocationSpecified(); + + verify(initializer).init(CollectionUtils.createProperties( + Collections.singletonMap(SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, + xmlLocation))); + } + +} diff --git a/src/test/resources/SpringServerLauncherCacheProviderIntegrationTest-context.xml b/src/test/resources/SpringServerLauncherCacheProviderIntegrationTest-context.xml new file mode 100644 index 00000000..c8c078bd --- /dev/null +++ b/src/test/resources/SpringServerLauncherCacheProviderIntegrationTest-context.xml @@ -0,0 +1,25 @@ + + + + + + SpringContextBootstrappingInitializerTest + false + 0 + config + + + + + + +