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 <jblum@pivotal.io>
This commit is contained in:
Dan Smith
2016-02-29 18:08:19 -08:00
committed by John Blum
parent fe4527a45a
commit b02abf2c1e
5 changed files with 292 additions and 0 deletions

View File

@@ -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();
}
}

View File

@@ -0,0 +1 @@
org.springframework.data.gemfire.support.SpringServerLauncherCacheProvider

View File

@@ -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());
}
}

View File

@@ -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)));
}
}

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- data source Spring XML configuration file and meta-data, using GemFire -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xmlns:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<util:properties id="gemfireProperties">
<prop key="name">SpringContextBootstrappingInitializerTest</prop>
<prop key="statistic-sampling-enabled">false</prop>
<prop key="mcast-port">0</prop>
<prop key="log-level">config</prop>
</util:properties>
<gfe:cache properties-ref="gemfireProperties" use-bean-factory-locator="false"
critical-heap-percentage="55"/>
<gfe:replicated-region id="TestRegion" persistent="false"/>
</beans>