diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java new file mode 100644 index 00000000..560ac6d6 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketFactoryBean.java @@ -0,0 +1,66 @@ +/* + * Copyright 2012-2015 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 com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import com.couchbase.client.java.CouchbaseBucket; + +import org.springframework.beans.factory.config.AbstractFactoryBean; + +/** + * The Factory Bean to help {@link CouchbaseBucketParser} constructing a {@link Bucket} from a given + * {@link Cluster} reference. + * + * @author Simon Baslé + */ +public class CouchbaseBucketFactoryBean extends AbstractFactoryBean { + + private final Cluster cluster; + private final String bucketName; + private final String bucketPassword; + + public CouchbaseBucketFactoryBean(Cluster cluster) { + this(cluster, null, null); + } + + public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName) { + this(cluster, bucketName, null); + } + + public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName, String bucketPassword) { + this.cluster = cluster; + this.bucketName = bucketName; + this.bucketPassword = bucketPassword; + } + + @Override + public Class getObjectType() { + return CouchbaseBucket.class; + } + + @Override + protected Bucket createInstance() throws Exception { + if (bucketName == null) { + return cluster.openBucket(); + } else if (bucketPassword == null) { + return cluster.openBucket(bucketName); + } else { + return cluster.openBucket(bucketName, bucketPassword); + } + } +} diff --git a/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java new file mode 100644 index 00000000..431b2456 --- /dev/null +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseBucketParser.java @@ -0,0 +1,103 @@ +/* + * Copyright 2012-2015 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 com.couchbase.client.java.Bucket; +import com.couchbase.client.java.Cluster; +import org.w3c.dom.Element; + +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.util.StringUtils; + +/** + * The parser for XML definition of a {@link Bucket}, to be constructed from a {@link Cluster} reference. + * If no reference is given, the default reference {@value BeanNames#COUCHBASE_CLUSTER} is used. + * + * See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}. + * + * @author Simon Baslé + */ +public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser { + + /** + * The cluster-ref attribute in a bucket definition defines the cluster to build from. + */ + public static final String CLUSTER_REF_ATTR = "cluster-ref"; + + /** + * The bucketName attribute in a bucket definition defines the name of the bucket to open. + */ + public static final String BUCKETNAME_ATTR = "bucketName"; + + /** + * The bucketPassword attribute in a bucket definition defines the password of the bucket to open. + */ + public static final String BUCKETPASSWORD_ATTR = "bucketPassword"; + + /** + * Resolve the bean ID and assign a default if not set. + * + * @param element the XML element which contains the attributes. + * @param definition the bean definition to work with. + * @param parserContext encapsulates the parsing state and configuration. + * @return the ID to work with. + */ + @Override + 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_BUCKET; + } + + /** + * Defines the bean class that will be constructed. + * + * @param element the XML element which contains the attributes. + * @return the class type to instantiate. + */ + @Override + protected Class getBeanClass(final Element element) { + return CouchbaseBucketFactoryBean.class; + } + + /** + * Parse the bean definition and build up the bean. + * + * @param element the XML element which contains the attributes. + * @param builder the builder which builds the bean. + */ + @Override + protected void doParse(final Element element, final BeanDefinitionBuilder builder) { + String clusterRef = element.getAttribute(CLUSTER_REF_ATTR); + if (!StringUtils.hasText(clusterRef)) { + clusterRef = BeanNames.COUCHBASE_CLUSTER; + } + builder.addConstructorArgReference(clusterRef); + + String bucketName = element.getAttribute(BUCKETNAME_ATTR); + if (StringUtils.hasText(bucketName)) { + builder.addConstructorArgValue(bucketName); + } + + String bucketPassword = element.getAttribute(BUCKETPASSWORD_ATTR); + if (StringUtils.hasText(bucketPassword)) { + builder.addConstructorArgValue(bucketPassword); + } + } +} 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 88a2ba33..ee2ae154 100644 --- a/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java +++ b/src/main/java/org/springframework/data/couchbase/config/CouchbaseNamespaceHandler.java @@ -34,9 +34,9 @@ public class CouchbaseNamespaceHandler extends NamespaceHandlerSupport { */ public final void init() { //TODO repositories (CouchbaseRepositoryConfigurationExtension and RepositoryBeanDefinitionParser) - //TODO bucket - registerBeanDefinitionParser("cluster", new CouchbaseClusterParser()); registerBeanDefinitionParser("env", new CouchbaseEnvironmentParser()); + registerBeanDefinitionParser("cluster", new CouchbaseClusterParser()); + registerBeanDefinitionParser("bucket", new CouchbaseBucketParser()); registerBeanDefinitionParser("jmx", new CouchbaseJmxParser()); registerBeanDefinitionParser("template", new CouchbaseTemplateParser()); //TODO translation service diff --git a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd index 78af46ba..23f3fd24 100644 --- a/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd +++ b/src/main/resources/org/springframework/data/couchbase/config/spring-couchbase-2.0.xsd @@ -30,6 +30,18 @@ + + + + + + + + + + + + diff --git a/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java b/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java new file mode 100644 index 00000000..38b61f43 --- /dev/null +++ b/src/test/java/org/springframework/data/couchbase/config/CouchbaseBucketParserTest.java @@ -0,0 +1,218 @@ +/* + * Copyright 2012-2015 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 static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +import java.util.List; + +import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; +import org.springframework.core.io.ClassPathResource; + +public class CouchbaseBucketParserTest { + + + private static DefaultListableBeanFactory factory; + + @BeforeClass + public static void setUp() { + factory = new DefaultListableBeanFactory(); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory); + int n = reader.loadBeanDefinitions(new ClassPathResource("configurations/couchbaseBucket-bean.xml")); + System.out.println(n); + } + + @AfterClass + public static void tearDown() { + } + + @Test + public void testDefaultBucketNoCluster() { + BeanDefinition def = factory.getBeanDefinition("bucketDefaultNoCluster"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(clusterRef.getBeanName(), is(equalTo(BeanNames.COUCHBASE_CLUSTER))); + } + + @Test + public void testDefaultBucket() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketDefault"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + } + + @Test + public void testBucketWithName() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketWithName"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(2))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + + ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues() + .getArgumentValue(1, Object.class); + assertThat(nameHolder.getValue(), is(instanceOf(String.class))); + assertThat(nameHolder.getValue().toString(), is((equalTo("toto")))); + } + + @Test + public void testBucketWithNameAndPassword() throws Exception { + BeanDefinition def = factory.getBeanDefinition("bucketWithNameAndPassword"); + + assertThat(def, is(notNullValue())); + assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(3))); + assertThat(def.getPropertyValues().size(), is(equalTo(0))); + + ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() + .getArgumentValue(0, Object.class); + assertThat(holder.getValue(), is(instanceOf(RuntimeBeanReference.class))); + + RuntimeBeanReference clusterRef = (RuntimeBeanReference) holder.getValue(); + assertThat(clusterRef.getBeanName(), is(equalTo("clusterDefault"))); + + ConstructorArgumentValues.ValueHolder nameHolder = def.getConstructorArgumentValues() + .getArgumentValue(1, Object.class); + assertThat(nameHolder.getValue(), is(instanceOf(String.class))); + assertThat(nameHolder.getValue().toString(), is((equalTo("test")))); + + ConstructorArgumentValues.ValueHolder passwordHolder = def.getConstructorArgumentValues() + .getArgumentValue(2, Object.class); + assertThat(passwordHolder.getValue(), is(instanceOf(String.class))); + assertThat(passwordHolder.getValue().toString(), is((equalTo("123")))); + + } + +// @Test +// public void testClusterWithNodes() { +// BeanDefinition def = factory.getBeanDefinition("clusterWithNodes"); +// +// assertThat(def, is(notNullValue())); +// assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); +// assertThat(def.getPropertyValues().size(), is(equalTo(0))); +// assertThat(def.getFactoryMethodName(), is(equalTo("create"))); +// +// ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() +// .getArgumentValue(0, List.class); +// assertThat(holder.getValue(), is(instanceOf(List.class))); +// List nodes = (List) holder.getValue(); +// +// assertThat(nodes.size(), is(equalTo(2))); +// assertThat((String) nodes.get(0), is(equalTo("192.1.2.3"))); +// assertThat((String) nodes.get(1), is(equalTo("192.4.5.6"))); +// } +// +// @Test +// public void testClusterWithEnvInline() { +// BeanDefinition def = factory.getBeanDefinition("clusterWithEnvInline"); +// +// assertThat(def, is(notNullValue())); +// assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); +// assertThat(def.getPropertyValues().size(), is(equalTo(0))); +// +// ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() +// .getArgumentValue(0, CouchbaseEnvironment.class); +// GenericBeanDefinition envDef = (GenericBeanDefinition) holder.getValue(); +// +// assertThat(envDef.getBeanClassName(), is(equalTo(CouchbaseEnvironmentFactoryBean.class.getName()))); +// assertThat("unexpected attribute", envDef.getPropertyValues().contains("managementTimeout")); +// } +// +// @Test +// public void testClusterWithEnvRef() { +// BeanDefinition def = factory.getBeanDefinition("clusterWithEnvRef"); +// +// assertThat(def, is(notNullValue())); +// assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(1))); +// assertThat(def.getPropertyValues().size(), is(equalTo(0))); +// +// ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues() +// .getArgumentValue(0, CouchbaseEnvironment.class); +// +// assertThat(holder.getValue(), instanceOf(RuntimeBeanReference.class)); +// RuntimeBeanReference envRef = (RuntimeBeanReference) holder.getValue(); +// +// assertThat(envRef.getBeanName(), is(equalTo("someEnv"))); +// } +// @Test +// public void testClusterConfigurationPrecedence() { +// BeanDefinition def = factory.getBeanDefinition("clusterWithAll"); +// +// assertThat(def, is(notNullValue())); +// assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(2))); +// assertThat(def.getPropertyValues().size(), is(equalTo(0))); +// assertThat(def.getFactoryMethodName(), is(equalTo("create"))); +// +// assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(0).getValue(), +// instanceOf(GenericBeanDefinition.class)); +// assertThat(def.getConstructorArgumentValues().getIndexedArgumentValues().get(1).getValue(), +// instanceOf(List.class)); +// +// ConstructorArgumentValues.ValueHolder holderEnv = def.getConstructorArgumentValues() +// .getArgumentValue(0, CouchbaseEnvironment.class); +// GenericBeanDefinition envDef = (GenericBeanDefinition) holderEnv.getValue(); +// +// assertThat(envDef.getBeanClassName(), is(equalTo(CouchbaseEnvironmentFactoryBean.class.getName()))); +// assertThat("unexpected attribute", envDef.getPropertyValues().contains("autoreleaseAfter")); +// +// ConstructorArgumentValues.ValueHolder holderNodes = def.getConstructorArgumentValues() +// .getArgumentValue(1, List.class); +// List nodes = (List) holderNodes.getValue(); +// +// assertThat(nodes.size(), is(equalTo(2))); +// assertThat((String) nodes.get(0), is(equalTo("2.2.2.2"))); +// assertThat((String) nodes.get(1), is(equalTo("4.4.4.4"))); +// } +} \ No newline at end of file diff --git a/src/test/resources/configurations/couchbaseBucket-bean.xml b/src/test/resources/configurations/couchbaseBucket-bean.xml new file mode 100644 index 00000000..2c7e9e4d --- /dev/null +++ b/src/test/resources/configurations/couchbaseBucket-bean.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file