Initial implementation of JIRA improvement SGF-191 enabling Spring Data GemFire to lookup and auto register all GemFire Cache Regions not explicitly defined in the Spring context as Spring beans.
This commit is contained in:
@@ -28,15 +28,19 @@ import com.gemstone.gemfire.cache.client.ClientRegionFactory;
|
||||
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
|
||||
|
||||
/**
|
||||
* @author David Turanski
|
||||
* a {@link BeanFactoryPostProcessor} to register a Client Region bean, if necessary, for each Region accessible
|
||||
* A {@link BeanFactoryPostProcessor} to register a Client Region bean, if necessary, for each Region accessible
|
||||
* to a Gemfire data source. If the Region is already defined, the definition will not be overridden.
|
||||
*
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
*/
|
||||
public class GemfireDataSourcePostProcessor implements BeanFactoryPostProcessor {
|
||||
|
||||
private static Log logger = LogFactory.getLog(GemfireDataSourcePostProcessor.class);
|
||||
|
||||
private final ClientCache cache;
|
||||
|
||||
public GemfireDataSourcePostProcessor(ClientCache cache) {
|
||||
public GemfireDataSourcePostProcessor(final ClientCache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@@ -46,37 +50,41 @@ public class GemfireDataSourcePostProcessor implements BeanFactoryPostProcessor
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
createClientRegions(beanFactory);
|
||||
|
||||
}
|
||||
|
||||
private void createClientRegions(ConfigurableListableBeanFactory beanFactory) {
|
||||
GemfireFunctionOperations template = new GemfireOnServersFunctionTemplate(cache);
|
||||
Iterable<String> regionNames = template.executeAndExtract(new ListRegionsOnServerFunction());
|
||||
GemfireFunctionOperations functionTemplate = new GemfireOnServersFunctionTemplate(cache);
|
||||
|
||||
Iterable<String> regionNames = functionTemplate.executeAndExtract(new ListRegionsOnServerFunction());
|
||||
|
||||
ClientRegionFactory<?, ?> clientRegionFactory = null;
|
||||
|
||||
if (regionNames != null && regionNames.iterator().hasNext()) {
|
||||
clientRegionFactory = cache.createClientRegionFactory(ClientRegionShortcut.PROXY);
|
||||
}
|
||||
|
||||
for (String regionName : regionNames) {
|
||||
boolean createRegion = true;
|
||||
|
||||
if (beanFactory.containsBean(regionName)) {
|
||||
Object existingBean = beanFactory.getBean(regionName);
|
||||
Assert.isTrue(beanFactory.getBean(regionName) instanceof Region, String.format(
|
||||
"cannot create a ClientRegion bean named %s. A bean with this name of type %s already exists.",
|
||||
Assert.isTrue(existingBean instanceof Region, String.format(
|
||||
"Cannot create a ClientRegion bean named '%1$s'. A bean with this name of type '%2$s' already exists.",
|
||||
regionName, existingBean.getClass().getName()));
|
||||
createRegion = false;
|
||||
}
|
||||
|
||||
if (createRegion) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("creating client region for %s", regionName));
|
||||
logger.debug(String.format("Creating Client Region bean with name '%s'...", regionName));
|
||||
}
|
||||
beanFactory.registerSingleton(regionName, clientRegionFactory.create(regionName));
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("a region named %s is already defined",regionName));
|
||||
logger.debug(String.format("A Region named '%s' is already defined.", regionName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* The AutoRegionLookupBeanDefinitionParser class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.support.AbstractBeanDefinition
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
* @see org.springframework.beans.factory.xml.BeanDefinitionParser
|
||||
* @see org.springframework.beans.factory.xml.ParserContext
|
||||
* @see org.w3c.dom.Element
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class AutoRegionLookupBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
public BeanDefinition parse(final Element element, final ParserContext parserContext) {
|
||||
registerAutoRegionLookupBeanPostProcessor(element, parserContext);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerAutoRegionLookupBeanPostProcessor(final Element element, final ParserContext parserContext) {
|
||||
AbstractBeanDefinition autoRegionLookupBeanPostProcessor = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(AutoRegionLookupBeanPostProcessor.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
|
||||
.getBeanDefinition();
|
||||
|
||||
autoRegionLookupBeanPostProcessor.setSource(parserContext.extractSource(element));
|
||||
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(autoRegionLookupBeanPostProcessor,
|
||||
parserContext.getRegistry());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.config;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* The AutoRegionLookupBeanPostProcessor class is a Spring BeanPostProcessor that post processes a GemFireCache by
|
||||
* registering all Cache Regions that have not been explicitly defined in the Spring application context. This is
|
||||
* usually the case for Regions that have been defined in GemFire native cache.xml or defined use GemFire 8's new
|
||||
* cluster-based configuration service.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see org.springframework.beans.factory.BeanFactoryAware
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
* @see com.gemstone.gemfire.cache.GemFireCache
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class AutoRegionLookupBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
@Override
|
||||
public final void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
|
||||
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
|
||||
String.format("The BeanFactory reference (%1$s) must be an instance of ConfigurableListableBeanFactory!",
|
||||
ObjectUtils.nullSafeClassName(beanFactory)));
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
|
||||
protected ConfigurableListableBeanFactory getBeanFactory() {
|
||||
Assert.state(this.beanFactory != null, "A reference to the BeanFactory was not properly configured and initialized!");
|
||||
return this.beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
|
||||
if (bean instanceof GemFireCache) {
|
||||
registerCacheRegionsAsBeans((GemFireCache) bean);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void registerCacheRegionsAsBeans(final GemFireCache cache) {
|
||||
for (Region region : cache.rootRegions()) {
|
||||
registerRegionAsBean(region);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerRegionAsBean(final Region<?, ?> region) {
|
||||
if (region != null) {
|
||||
String regionBeanName = getBeanName(region);
|
||||
|
||||
if (!getBeanFactory().containsBean(regionBeanName)) {
|
||||
getBeanFactory().registerSingleton(regionBeanName, region);
|
||||
}
|
||||
|
||||
for (Region<?, ?> subregion : nullSafeSubregions(region)) {
|
||||
registerRegionAsBean(subregion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Set<Region<?, ?>> nullSafeSubregions(final Region<?, ?> parentRegion) {
|
||||
Set<Region<?, ?>> subregions = parentRegion.subregions(false);
|
||||
return (subregions != null ? subregions : Collections.<Region<?, ?>>emptySet());
|
||||
}
|
||||
|
||||
private String getBeanName(final Region region) {
|
||||
String regionFullPath = region.getFullPath();
|
||||
return (regionFullPath.lastIndexOf(Region.SEPARATOR) > 0 ? regionFullPath : region.getName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author David Turanski
|
||||
*
|
||||
* @author John Blum
|
||||
*/
|
||||
public class GemfireDataSourceParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
@@ -32,37 +32,38 @@ public class GemfireDataSourceParser extends AbstractBeanDefinitionParser {
|
||||
*/
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
AbstractBeanDefinition poolDefinition = (AbstractBeanDefinition) new PoolParser().parse(element, parserContext);
|
||||
MutablePropertyValues poolProps = poolDefinition.getPropertyValues();
|
||||
|
||||
poolProps.add("name", GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
|
||||
MutablePropertyValues poolProperties = poolDefinition.getPropertyValues();
|
||||
|
||||
poolProperties.add("name", GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
|
||||
|
||||
if (!element.hasAttribute("subscription-enabled")) {
|
||||
poolProps.add("subscriptionEnabled", true);
|
||||
poolProperties.add("subscriptionEnabled", true);
|
||||
}
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, poolDefinition);
|
||||
|
||||
AbstractBeanDefinition clientCacheDefinition = (AbstractBeanDefinition) new ClientCacheParser().parse(element,
|
||||
parserContext);
|
||||
AbstractBeanDefinition clientCacheDefinition = (AbstractBeanDefinition) new ClientCacheParser()
|
||||
.parse(element, parserContext);
|
||||
|
||||
MutablePropertyValues props = clientCacheDefinition.getPropertyValues();
|
||||
|
||||
MutablePropertyValues clientCacheProperties = clientCacheDefinition.getPropertyValues();
|
||||
|
||||
props.add("pool", poolDefinition);
|
||||
|
||||
clientCacheDefinition.setPropertyValues(props);
|
||||
clientCacheProperties.add("pool", poolDefinition);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME,
|
||||
clientCacheDefinition);
|
||||
clientCacheDefinition);
|
||||
|
||||
System.out.println("registered " + GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME + ":"
|
||||
+ clientCacheDefinition.getBeanClassName());
|
||||
System.out.printf("Registered GemFire Client Cache bean '%1$s' of type '%2$s'%n",
|
||||
GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, clientCacheDefinition.getBeanClassName());
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
GemfireDataSourcePostProcessor.class);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(GemfireDataSourcePostProcessor.class);
|
||||
builder.addConstructorArgReference(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
|
||||
|
||||
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,14 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Namespace handler for GemFire definitions.
|
||||
* Spring NamespaceHandler for GemFire XML namespace (XSD) bean definitions.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.xml.NamespaceHandlerSupport
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class GemfireNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
protected static final List<String> GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender",
|
||||
@@ -48,11 +51,10 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("cache", new CacheParser());
|
||||
registerBeanDefinitionParser("cache-server", new CacheServerParser());
|
||||
registerBeanDefinitionParser("client-cache", new ClientCacheParser());
|
||||
registerBeanDefinitionParser("client-region", new ClientRegionParser());
|
||||
registerBeanDefinitionParser("client-region-template", new ClientRegionParser());
|
||||
registerBeanDefinitionParser("auto-region-lookup", new AutoRegionLookupBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("lookup-region", new LookupRegionParser());
|
||||
registerBeanDefinitionParser("region-template", new TemplateRegionParser());
|
||||
registerBeanDefinitionParser("local-region", new LocalRegionParser());
|
||||
@@ -63,14 +65,17 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
|
||||
registerBeanDefinitionParser("replicated-region-template", new ReplicatedRegionParser());
|
||||
registerBeanDefinitionParser("async-event-queue", new AsyncEventQueueParser());
|
||||
registerBeanDefinitionParser("disk-store", new DiskStoreParser());
|
||||
registerBeanDefinitionParser("function-service", new FunctionServiceParser());
|
||||
registerBeanDefinitionParser("gateway-hub", new GatewayHubParser());
|
||||
registerBeanDefinitionParser("gateway-receiver", new GatewayReceiverParser());
|
||||
registerBeanDefinitionParser("gateway-sender", new GatewaySenderParser());
|
||||
registerBeanDefinitionParser("index", new IndexParser());
|
||||
registerBeanDefinitionParser("pool", new PoolParser());
|
||||
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
|
||||
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
|
||||
registerBeanDefinitionParser("function-service", new FunctionServiceParser());
|
||||
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
|
||||
registerBeanDefinitionParser("client-cache", new ClientCacheParser());
|
||||
registerBeanDefinitionParser("client-region", new ClientRegionParser());
|
||||
registerBeanDefinitionParser("client-region-template", new ClientRegionParser());
|
||||
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
|
||||
registerBeanDefinitionParser("pool", new PoolParser());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -431,6 +431,16 @@ The name of the bean referred by this declaration. If no reference exists, use a
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
<!-- -->
|
||||
<xsd:element name="auto-region-lookup">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
GFE namespace element enabling GemFire Cache Regions to be automatically looked up and defined as beans in the Spring
|
||||
context when those Regions are defined outside of Spring config, such as in GemFire's native cache.xml or with
|
||||
GemFire 8's new cluster-based configuration service.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="baseLookupRegionType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
Reference in New Issue
Block a user