diff --git a/src/main/java/org/springframework/data/gemfire/client/GemfireDataSourcePostProcessor.java b/src/main/java/org/springframework/data/gemfire/client/GemfireDataSourcePostProcessor.java index 5377364b..aa401d6d 100644 --- a/src/main/java/org/springframework/data/gemfire/client/GemfireDataSourcePostProcessor.java +++ b/src/main/java/org/springframework/data/gemfire/client/GemfireDataSourcePostProcessor.java @@ -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 regionNames = template.executeAndExtract(new ListRegionsOnServerFunction()); + GemfireFunctionOperations functionTemplate = new GemfireOnServersFunctionTemplate(cache); + + Iterable 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)); } } } } + } diff --git a/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanDefinitionParser.java b/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanDefinitionParser.java new file mode 100644 index 00000000..33d36b6f --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanDefinitionParser.java @@ -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()); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanPostProcessor.java b/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanPostProcessor.java new file mode 100644 index 00000000..4fc5f785 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/AutoRegionLookupBeanPostProcessor.java @@ -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> nullSafeSubregions(final Region parentRegion) { + Set> subregions = parentRegion.subregions(false); + return (subregions != null ? subregions : Collections.>emptySet()); + } + + private String getBeanName(final Region region) { + String regionFullPath = region.getFullPath(); + return (regionFullPath.lastIndexOf(Region.SEPARATOR) > 0 ? regionFullPath : region.getName()); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/GemfireDataSourceParser.java b/src/main/java/org/springframework/data/gemfire/config/GemfireDataSourceParser.java index 60dbc836..381f3fbd 100644 --- a/src/main/java/org/springframework/data/gemfire/config/GemfireDataSourceParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/GemfireDataSourceParser.java @@ -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; } diff --git a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java index f15013f9..4d433a82 100644 --- a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java +++ b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java @@ -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 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()); } + } diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd index dde0856c..22f3e441 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd @@ -431,6 +431,16 @@ The name of the bean referred by this declaration. If no reference exists, use a + + + + + +