/* * 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.xml; import java.util.List; import org.apache.geode.internal.datasource.ConfigProperty; import org.springframework.beans.factory.BeanDefinitionStoreException; 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.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.gemfire.CacheFactoryBean; import org.springframework.data.gemfire.config.support.CustomEditorBeanFactoryPostProcessor; import org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFactoryPostProcessor; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; /** * Bean definition parser for the <gfe:cache> SDG XML namespace (XSD) element. * * @author Costin Leau * @author Oliver Gierke * @author David Turanski * @author John Blum * @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser * @see org.springframework.data.gemfire.CacheFactoryBean */ class CacheParser extends AbstractSingleBeanDefinitionParser { /** * {@inheritDoc} */ @Override protected Class<?> getBeanClass(Element element) { return CacheFactoryBean.class; } /** * {@inheritDoc} */ @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, builder); registerGemFireBeanFactoryPostProcessors(getRegistry(parserContext)); ParsingUtils.setPropertyValue(element, builder, "cache-xml-location", "cacheXml"); ParsingUtils.setPropertyReference(element, builder, "properties-ref", "properties"); ParsingUtils.setPropertyValue(element, builder, "use-bean-factory-locator"); ParsingUtils.setPropertyValue(element, builder, "close"); ParsingUtils.setPropertyValue(element, builder, "copy-on-read"); ParsingUtils.setPropertyValue(element, builder, "critical-heap-percentage"); ParsingUtils.setPropertyValue(element, builder, "eviction-heap-percentage"); ParsingUtils.setPropertyValue(element, builder, "enable-auto-reconnect"); ParsingUtils.setPropertyValue(element, builder, "lock-lease"); ParsingUtils.setPropertyValue(element, builder, "lock-timeout"); ParsingUtils.setPropertyValue(element, builder, "message-sync-interval"); parsePdxDiskStore(element, parserContext, builder); ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields"); ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized"); ParsingUtils.setPropertyValue(element, builder, "pdx-persistent"); ParsingUtils.setPropertyReference(element, builder, "pdx-serializer-ref", "pdxSerializer"); ParsingUtils.setPropertyValue(element, builder, "search-timeout"); ParsingUtils.setPropertyValue(element, builder, "use-cluster-configuration"); List<Element> txListeners = DomUtils.getChildElementsByTagName(element, "transaction-listener"); if (!CollectionUtils.isEmpty(txListeners)) { ManagedList<Object> transactionListeners = new ManagedList<Object>(); for (Element txListener : txListeners) { transactionListeners.add(ParsingUtils.parseRefOrNestedBeanDeclaration( txListener, parserContext, builder)); } builder.addPropertyValue("transactionListeners", transactionListeners); } Element txWriter = DomUtils.getChildElementByTagName(element, "transaction-writer"); if (txWriter != null) { builder.addPropertyValue("transactionWriter", ParsingUtils.parseRefOrNestedBeanDeclaration( txWriter, parserContext, builder)); } Element gatewayConflictResolver = DomUtils.getChildElementByTagName(element, "gateway-conflict-resolver"); if (gatewayConflictResolver != null) { ParsingUtils.throwExceptionIfNotGemfireV7(element.getLocalName(), "gateway-conflict-resolver", parserContext); builder.addPropertyValue("gatewayConflictResolver", ParsingUtils.parseRefOrSingleNestedBeanDeclaration( gatewayConflictResolver, parserContext, builder)); } parseDynamicRegionFactory(element, builder); parseJndiBindings(element, builder); } /* (non-Javadoc) */ protected BeanDefinitionRegistry getRegistry(ParserContext parserContext) { return parserContext.getRegistry(); } /* (non-Javadoc) */ void registerGemFireBeanFactoryPostProcessors(BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerWithGeneratedName(BeanDefinitionBuilder.genericBeanDefinition( CustomEditorBeanFactoryPostProcessor.class).getBeanDefinition(), registry); } /* (non-Javadoc) */ private void parsePdxDiskStore(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { ParsingUtils.setPropertyValue(element, builder, "pdx-disk-store", "pdxDiskStoreName"); final String pdxDiskStoreName = element.getAttribute("pdx-disk-store"); if (!StringUtils.isEmpty(pdxDiskStoreName)) { registerPdxDiskStoreAwareBeanFactoryPostProcessor(getRegistry(parserContext), pdxDiskStoreName); } } /* (non-Javadoc) */ void registerPdxDiskStoreAwareBeanFactoryPostProcessor(BeanDefinitionRegistry registry, String pdxDiskStoreName) { BeanDefinitionReaderUtils.registerWithGeneratedName( createPdxDiskStoreAwareBeanFactoryPostProcessorBeanDefinition(pdxDiskStoreName), registry); } /* (non-Javadoc) */ private AbstractBeanDefinition createPdxDiskStoreAwareBeanFactoryPostProcessorBeanDefinition(String pdxDiskStoreName) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( PdxDiskStoreAwareBeanFactoryPostProcessor.class); builder.addConstructorArgValue(pdxDiskStoreName); return builder.getBeanDefinition(); } /* (non-Javadoc) */ private void parseDynamicRegionFactory(Element element, BeanDefinitionBuilder builder) { Element dynamicRegionFactory = DomUtils.getChildElementByTagName(element, "dynamic-region-factory"); if (dynamicRegionFactory != null) { BeanDefinitionBuilder dynamicRegionSupport = buildDynamicRegionSupport(dynamicRegionFactory); postProcessDynamicRegionSupport(element, dynamicRegionSupport); builder.addPropertyValue("dynamicRegionSupport", dynamicRegionSupport.getBeanDefinition()); } } /* (non-Javadoc) */ private BeanDefinitionBuilder buildDynamicRegionSupport(Element dynamicRegionFactory) { if (dynamicRegionFactory != null) { BeanDefinitionBuilder dynamicRegionSupport = BeanDefinitionBuilder.genericBeanDefinition( CacheFactoryBean.DynamicRegionSupport.class); String diskDirectory = dynamicRegionFactory.getAttribute("disk-dir"); if (StringUtils.hasText(diskDirectory)) { dynamicRegionSupport.addPropertyValue("diskDir", diskDirectory); } String persistent = dynamicRegionFactory.getAttribute("persistent"); if (StringUtils.hasText(persistent)) { dynamicRegionSupport.addPropertyValue("persistent", persistent); } String registerInterest = dynamicRegionFactory.getAttribute("register-interest"); if (StringUtils.hasText(registerInterest)) { dynamicRegionSupport.addPropertyValue("registerInterest", registerInterest); } return dynamicRegionSupport; } return null; } /** * @param dynamicRegionSupport {@link BeanDefinitionBuilder} for <gfe:dynamic-region-factory> element. */ protected void postProcessDynamicRegionSupport(Element element, BeanDefinitionBuilder dynamicRegionSupport) { } /* (non-Javadoc) */ private void parseJndiBindings(Element element, BeanDefinitionBuilder builder) { List<Element> jndiBindings = DomUtils.getChildElementsByTagName(element, "jndi-binding"); if (!CollectionUtils.isEmpty(jndiBindings)) { ManagedList<Object> jndiDataSources = new ManagedList<Object>(jndiBindings.size()); for (Element jndiBinding : jndiBindings) { BeanDefinitionBuilder jndiDataSource = BeanDefinitionBuilder.genericBeanDefinition( CacheFactoryBean.JndiDataSource.class); // NOTE 'jndi-name' and 'type' are required by the XSD so we should have at least 2 attributes. NamedNodeMap attributes = jndiBinding.getAttributes(); ManagedMap<String, String> jndiAttributes = new ManagedMap<String, String>(attributes.getLength()); for (int index = 0, length = attributes.getLength(); index < length; index++) { Attr attribute = (Attr) attributes.item(index); jndiAttributes.put(attribute.getLocalName(), attribute.getValue()); } jndiDataSource.addPropertyValue("attributes", jndiAttributes); List<Element> jndiProps = DomUtils.getChildElementsByTagName(jndiBinding, "jndi-prop"); if (!CollectionUtils.isEmpty(jndiProps)) { ManagedList<Object> props = new ManagedList<Object>(jndiProps.size()); for (Element jndiProp : jndiProps) { String key = jndiProp.getAttribute("key"); String type = jndiProp.getAttribute("type"); String value = jndiProp.getTextContent(); type = (StringUtils.hasText(type) ? type : String.class.getName()); props.add(BeanDefinitionBuilder.genericBeanDefinition(ConfigProperty.class) .addConstructorArgValue(key) .addConstructorArgValue(value) .addConstructorArgValue(type) .getBeanDefinition()); } jndiDataSource.addPropertyValue("props", props); } jndiDataSources.add(jndiDataSource.getBeanDefinition()); } builder.addPropertyValue("jndiDataSources", jndiDataSources); } } /** * {@inheritDoc} */ @Override protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { String name = super.resolveId(element, definition, parserContext); if (!StringUtils.hasText(name)) { name = GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME; // Set Cache bean alias for backwards compatibility... parserContext.getRegistry().registerAlias(name, "gemfire-cache"); } return name; } }