From ab252f8924f2d6cd0f2a2d894b134ee5a9d75cc6 Mon Sep 17 00:00:00 2001 From: Michael Nitschinger Date: Wed, 17 Jul 2013 14:58:51 +0200 Subject: [PATCH] DATACOUCH-6 - Add simple support for XML config --- .../data/couchbase/config/BeanNames.java | 28 ++++++++ .../couchbase/config/CouchbaseJmxParser.java | 66 ++++++++++++++++++ .../config/CouchbaseNamespaceHandler.java | 5 +- .../couchbase/config/CouchbaseParser.java | 67 ++++++++++++++----- .../config/CouchbaseTemplateParser.java | 55 +++++++++++++++ .../couchbase/core/CouchbaseFactoryBean.java | 2 +- .../CouchbaseParserIntegrationTest.java | 11 ++- ...ouchbaseTemplateParserIntegrationTest.java | 53 +++++++++++++++ .../resources/namespace/couchbase-bean.xml | 4 +- .../namespace/couchbase-template-bean.xml | 12 ++++ 10 files changed, 277 insertions(+), 26 deletions(-) create mode 100644 src/main/java/org/springframework/data/couchbase/config/BeanNames.java create mode 100644 src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java create mode 100644 src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java create mode 100644 src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTest.java create mode 100644 src/test/resources/namespace/couchbase-template-bean.xml diff --git a/src/main/java/org/springframework/data/couchbase/config/BeanNames.java b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java new file mode 100644 index 00000000..eeb20484 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/BeanNames.java @@ -0,0 +1,28 @@ +/* + * Copyright 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.couchbase.config; + +/** + * @author Michael Nitschinger + */ +public class BeanNames { + static final String MAPPING_CONTEXT = "mappingContext"; + static final String COUCHBASE = "couchbase"; + static final String DB_FACTORY = "couchbaseDbFactory"; + static final String DEFAULT_CONVERTER_BEAN_NAME = "mappingConverter"; + static final String COUCHBASE_TEMPLATE = "couchbaseTemplate"; +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java new file mode 100644 index 00000000..229d62ff --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseJmxParser.java @@ -0,0 +1,66 @@ +/* + * Copyright 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.couchbase.config; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.couchbase.monitor.ClientInfo; +import org.springframework.data.couchbase.monitor.ClusterInfo; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * Enables Parsing of "" configurations. + * + * @author Michael Nitschinger + */ +public class CouchbaseJmxParser implements BeanDefinitionParser { + + public BeanDefinition parse(final Element element, final ParserContext parserContext) { + String name = element.getAttribute("couchbase-ref"); + if (!StringUtils.hasText(name)) { + name = BeanNames.COUCHBASE; + } + registerJmxComponents(name, element, parserContext); + return null; + } + + protected void registerJmxComponents(String refName, Element element, ParserContext parserContext) { + Object eleSource = parserContext.extractSource(element); + CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource); + + createBeanDefEntry(ClientInfo.class, compositeDef, refName, eleSource, parserContext); + createBeanDefEntry(ClusterInfo.class, compositeDef, refName, eleSource, parserContext); + + parserContext.registerComponent(compositeDef); + } + + protected void createBeanDefEntry(Class clazz, CompositeComponentDefinition compositeDef, + String refName, Object eleSource, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); + builder.getRawBeanDefinition().setSource(eleSource); + builder.addConstructorArgReference(refName); + BeanDefinition assertDef = builder.getBeanDefinition(); + String assertName = parserContext.getReaderContext().registerWithGeneratedName(assertDef); + compositeDef.addNestedComponent(new BeanComponentDefinition(assertDef, assertName)); + } + +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java index 10060d62..0b33b6f6 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java @@ -30,10 +30,9 @@ public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport { public void init() { RepositoryConfigurationExtension extension = new CouchbaseRepositoryConfigurationExtension(); - RepositoryBeanDefinitionParser repositoryBeanDefinitionParser = new RepositoryBeanDefinitionParser(extension); - registerBeanDefinitionParser("repositories", repositoryBeanDefinitionParser); - registerBeanDefinitionParser("mongo", new CouchbaseParser()); + registerBeanDefinitionParser("repositories", new RepositoryBeanDefinitionParser(extension)); + registerBeanDefinitionParser("couchbase", new CouchbaseParser()); registerBeanDefinitionParser("jmx", new CouchbaseJmxParser()); registerBeanDefinitionParser("template", new CouchbaseTemplateParser()); } diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java index 981806ac..3718a776 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseParser.java @@ -17,32 +17,65 @@ package org.springframework.data.couchbase.config; import com.couchbase.client.CouchbaseClient; -import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.data.config.BeanComponentDefinitionBuilder; -import org.springframework.data.config.ParsingUtils; +import org.springframework.data.couchbase.core.CouchbaseFactoryBean; +import org.springframework.util.StringUtils; import org.w3c.dom.Element; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; + + /** - * Parser for "" definitions. + * Parser for "" definitions. * * @author Michael Nitschinger */ -public class CouchbaseParser implements BeanDefinitionParser { +public class CouchbaseParser extends AbstractSingleBeanDefinitionParser { @Override - public BeanDefinition parse(final Element element, final ParserContext parserContext) { - Object source = parserContext.extractSource(element); - String id = element.getAttribute("id"); - - BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext); - - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CouchbaseClient.class); - builder.s - ParsingUtils.setPropertyValue(builder, element, "port", "port"); - ParsingUtils.setPropertyValue(builder, element, "host", "host"); - + protected Class getBeanClass(final Element element) { + return CouchbaseClient.class; } + + @Override + protected void doParse(final Element element, final BeanDefinitionBuilder bean) { + String host = element.getAttribute("host"); + bean.addConstructorArgValue( + convertHosts(StringUtils.hasText(host) ? host : CouchbaseFactoryBean.DEFAULT_NODE)); + String bucket = element.getAttribute("bucket"); + bean.addConstructorArgValue( + StringUtils.hasText(bucket) ? bucket : CouchbaseFactoryBean.DEFAULT_BUCKET); + String password = element.getAttribute("password"); + bean.addConstructorArgValue( + StringUtils.hasText(password) ? password : CouchbaseFactoryBean.DEFAULT_PASSWORD); + } + + protected String resolveId(final Element element, final AbstractBeanDefinition definition, + final ParserContext parserContext) { + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE; + } + + private List convertHosts(final String hosts) { + String[] split = hosts.split(","); + List nodes = new ArrayList(); + + try { + for (int i = 0; i < split.length; i++) { + nodes.add(new URI("http://" + split[i] + ":8091/pools")); + } + } catch (URISyntaxException ex) { + throw new BeanCreationException("Could not convert host list." + ex); + } + + return nodes; + } + } diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java new file mode 100644 index 00000000..b1e99f81 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseTemplateParser.java @@ -0,0 +1,55 @@ +/* + * Copyright 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.couchbase.config; + +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +/** + * @author Michael Nitschinger + */ +public class CouchbaseTemplateParser extends AbstractSingleBeanDefinitionParser { + + protected String resolveId(final Element element, final AbstractBeanDefinition definition, + final ParserContext parserContext) { + String id = super.resolveId(element, definition, parserContext); + return StringUtils.hasText(id) ? id : BeanNames.COUCHBASE_TEMPLATE; + } + + @Override + protected Class getBeanClass(final Element element) { + return CouchbaseTemplate.class; + } + + @Override + protected void doParse(final Element element, final BeanDefinitionBuilder bean) { + String converterRef = element.getAttribute("converter-ref"); + String dbRef = element.getAttribute("db-ref"); + + bean.addConstructorArgReference(StringUtils.hasText(dbRef) ? dbRef : BeanNames.COUCHBASE); + + if (StringUtils.hasText(converterRef)) { + bean.addConstructorArgReference(converterRef); + } + } + +} diff --git a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java b/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java index e47871ee..ae5d33da 100644 --- a/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java +++ b/src/main/java/org/springframework/data/couchbase/core/CouchbaseFactoryBean.java @@ -39,7 +39,7 @@ import java.util.concurrent.TimeUnit; * @author Michael Nitschinger */ public class CouchbaseFactoryBean implements FactoryBean, InitializingBean, - DisposableBean, PersistenceExceptionTranslator{ + DisposableBean, PersistenceExceptionTranslator { public static final String DEFAULT_NODE = "127.0.0.1"; public static final String DEFAULT_BUCKET = "default"; diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTest.java index 2f8c7ad3..eec1c334 100644 --- a/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTest.java +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseParserIntegrationTest.java @@ -18,7 +18,6 @@ package org.springframework.data.couchbase.config; import org.junit.Test; import org.junit.Before; -import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -27,6 +26,8 @@ import org.springframework.core.io.ClassPathResource; import java.util.List; +import static org.junit.Assert.assertEquals; + /** * @author Michael Nitschinger */ @@ -44,11 +45,15 @@ public class CouchbaseParserIntegrationTest { @Test public void readsCouchbaseAttributesCorrectly() { reader.loadBeanDefinitions(new ClassPathResource("namespace/couchbase-bean.xml")); + BeanDefinition definition = factory.getBeanDefinition("couchbase"); + assertEquals(3, definition.getConstructorArgumentValues().getArgumentCount()); - List values = definition.getPropertyValues().getPropertyValueList(); + definition = factory.getBeanDefinition("couchbase2"); + assertEquals(3, definition.getConstructorArgumentValues().getArgumentCount()); - System.out.println(values); + factory.getBean("couchbase"); + factory.getBean("couchbase2"); } } diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTest.java new file mode 100644 index 00000000..f83eae39 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseTemplateParserIntegrationTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 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.couchbase.config; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +import static org.junit.Assert.assertEquals; + +/** + * @author Michael Nitschinger + */ +public class CouchbaseTemplateParserIntegrationTest { + + DefaultListableBeanFactory factory; + BeanDefinitionReader reader; + + @Before + public void setUp() { + factory = new DefaultListableBeanFactory(); + reader = new XmlBeanDefinitionReader(factory); + } + + @Test + public void readsCouchbaseTemplateAttributesCorrectly() { + reader.loadBeanDefinitions(new ClassPathResource("namespace/couchbase-template-bean.xml")); + + BeanDefinition definition = factory.getBeanDefinition("couchbaseTemplate"); + assertEquals(1, definition.getConstructorArgumentValues().getArgumentCount()); + + factory.getBean("couchbaseTemplate"); + } + +} diff --git a/src/test/resources/namespace/couchbase-bean.xml b/src/test/resources/namespace/couchbase-bean.xml index 357c0e24..134736a4 100644 --- a/src/test/resources/namespace/couchbase-bean.xml +++ b/src/test/resources/namespace/couchbase-bean.xml @@ -5,8 +5,8 @@ xsi:schemaLocation="http://www.springframework.org/schema/data/couchbase http://www.springframework.org/schema/data/couchbase/spring-couchbase.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + \ No newline at end of file diff --git a/src/test/resources/namespace/couchbase-template-bean.xml b/src/test/resources/namespace/couchbase-template-bean.xml new file mode 100644 index 00000000..6ccb176b --- /dev/null +++ b/src/test/resources/namespace/couchbase-template-bean.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file