DATADOC-295 - Added ability to setup a SimpleMongoDbFactory using a MongoURI.

Extended SimpleMongoDbFactory with a constructor to take a MongoUri instance. Expose uri attribute at the db-factory namespace element.
This commit is contained in:
Oliver Gierke
2011-10-14 13:17:12 +02:00
parent 9f62efa47c
commit 33155ba0f4
8 changed files with 149 additions and 17 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011 by the original author(s).
* Copyright 2011 by the original author(s).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.data.mongodb.config;
import static org.springframework.data.mongodb.config.BeanNames.*;
import static org.springframework.data.mongodb.config.ParsingUtils.*;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -33,6 +34,7 @@ import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import com.mongodb.Mongo;
import com.mongodb.MongoURI;
/**
* {@link BeanDefinitionParser} to parse {@code db-factory} elements into {@link BeanDefinition}s.
@@ -54,31 +56,37 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String uri = element.getAttribute("uri");
String mongoRef = element.getAttribute("mongo-ref");
if (!StringUtils.hasText(mongoRef)) {
mongoRef = registerMongoBeanDefinition(element, parserContext);
}
// Database name
String dbname = element.getAttribute("dbname");
if (!StringUtils.hasText(dbname)) {
dbname = "db";
}
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element, parserContext);
// Common setup
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
ParsingUtils.setPropertyValue(element, dbFactoryBuilder, "write-concern", "writeConcern");
if (StringUtils.hasText(uri)) {
if(StringUtils.hasText(mongoRef) || StringUtils.hasText(dbname) || userCredentials != null) {
parserContext.getReaderContext().error("Configure either Mongo URI or details individually!", parserContext.extractSource(element));
}
dbFactoryBuilder.addConstructorArgValue(getMongoUri(uri));
return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element);
}
// Defaulting
mongoRef = StringUtils.hasText(mongoRef) ? mongoRef : registerMongoBeanDefinition(element, parserContext);
dbname = StringUtils.hasText(dbname) ? dbname : "db";
dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef));
dbFactoryBuilder.addConstructorArgValue(dbname);
BeanDefinition userCredentials = getUserCredentialsBeanDefinition(element);
if (userCredentials != null) {
dbFactoryBuilder.addConstructorArgValue(userCredentials);
}
ParsingUtils.setPropertyValue(element, dbFactoryBuilder, "write-concern", "writeConcern");
return dbFactoryBuilder.getBeanDefinition();
return getSourceBeanDefinition(dbFactoryBuilder, parserContext, element);
}
/**
@@ -105,7 +113,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
* @param element
* @return the {@link BeanDefinition} or {@literal null} if neither username nor password given.
*/
private BeanDefinition getUserCredentialsBeanDefinition(Element element) {
private BeanDefinition getUserCredentialsBeanDefinition(Element element, ParserContext context) {
String username = element.getAttribute("username");
String password = element.getAttribute("password");
@@ -118,6 +126,20 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(username) ? username : null);
userCredentialsBuilder.addConstructorArgValue(StringUtils.hasText(password) ? password : null);
return userCredentialsBuilder.getBeanDefinition();
return getSourceBeanDefinition(userCredentialsBuilder, context, element);
}
/**
* Creates a {@link BeanDefinition} for a {@link MongoURI}.
*
* @param uri
* @return
*/
private BeanDefinition getMongoUri(String uri) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MongoURI.class);
builder.addConstructorArgValue(uri);
return builder.getBeanDefinition();
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.mongodb.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.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
@@ -110,4 +112,19 @@ abstract class ParsingUtils {
builder.addPropertyValue(attrName, attr);
}
}
/**
* Returns the {@link BeanDefinition} built by the given {@link BeanDefinitionBuilder} enriched with source
* information derived from the given {@link Element}.
*
* @param builder must not be {@literal null}.
* @param context must not be {@literal null}.
* @param element must not be {@literal null}.
* @return
*/
static AbstractBeanDefinition getSourceBeanDefinition(BeanDefinitionBuilder builder, ParserContext context, Element element) {
AbstractBeanDefinition definition = builder.getBeanDefinition();
definition.setSource(context.extractSource(element));
return definition;
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.mongodb.core;
import java.net.UnknownHostException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -25,6 +27,8 @@ import org.springframework.util.Assert;
import com.mongodb.DB;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
import com.mongodb.MongoURI;
import com.mongodb.WriteConcern;
/**
@@ -69,6 +73,19 @@ public class SimpleMongoDbFactory implements DisposableBean, MongoDbFactory {
this.username = userCredentials.getUsername();
this.password = userCredentials.getPassword();
}
/**
* Creates a new {@link SimpleMongoDbFactory} instance from the given {@link MongoURI}.
*
* @param uri must not be {@literal null}.
* @throws MongoException
* @throws UnknownHostException
* @see MongoURI
*/
public SimpleMongoDbFactory(MongoURI uri) throws MongoException, UnknownHostException {
this(new Mongo(uri), uri.getDatabase(), new UserCredentials(uri.getUsername(), String.valueOf(uri.getPassword())));
}
/**
* Configures the {@link WriteConcern} to be used on the {@link DB} instance being created.

View File

@@ -87,6 +87,12 @@ The password to use when connecting to a MongoDB server.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="uri" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The Mongo URI string.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup ref="writeConcern" />
</xsd:complexType>
</xsd:element>

View File

@@ -23,10 +23,14 @@ import java.util.List;
import org.junit.Test;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import com.mongodb.Mongo;
import com.mongodb.MongoURI;
/**
* Integration tests for {@link MongoDbFactoryParser}.
@@ -60,4 +64,27 @@ public class MongoDbFactoryParserIntegrationTests {
Mongo mongo = factory.getBean(Mongo.class);
assertThat(mongo.getMongoOptions().maxAutoConnectRetryTime, is(27L));
}
/**
* @see DATADOC-295
*/
@Test
public void setsUpMongoDbFactoryUsingAMongoUri() {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("namespace/mongo-uri.xml"));
BeanDefinition definition = factory.getBeanDefinition("mongoDbFactory");
ConstructorArgumentValues constructorArguments = definition.getConstructorArgumentValues();
assertThat(constructorArguments.getArgumentCount(), is(1));
ValueHolder argument = constructorArguments.getArgumentValue(0, MongoURI.class);
assertThat(argument, is(notNullValue()));
}
/**
* @see DATADOC-295
*/
@Test(expected = BeanDefinitionParsingException.class)
public void rejectsUriPlusDetailedConfiguration() {
new XmlBeanFactory(new ClassPathResource("namespace/mongo-uri-and-details.xml"));
}
}

View File

@@ -16,12 +16,19 @@
package org.springframework.data.mongodb.core;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import java.net.UnknownHostException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.test.util.ReflectionTestUtils;
import com.mongodb.Mongo;
import com.mongodb.MongoURI;
/**
* Unit tests for {@link SimpleMongoDbFactory}.
@@ -53,6 +60,22 @@ public class SimpleMongoDbFactoryUnitTests {
new SimpleMongoDbFactory(mongo, "foo01231bar");
}
/**
* @see DATADOC-295
* @throws UnknownHostException
*/
@Test
public void mongoUriConstructor() throws UnknownHostException {
MongoURI mongoURI = new MongoURI("mongodb://myUsername:myPassword@localhost/myDatabase.myCollection");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongoURI);
assertThat(ReflectionTestUtils.getField(mongoDbFactory, "username").toString(), is("myUsername"));
assertThat(ReflectionTestUtils.getField(mongoDbFactory, "password").toString(), is("myPassword"));
assertThat(ReflectionTestUtils.getField(mongoDbFactory, "databaseName").toString(), is("myDatabase"));
assertThat(ReflectionTestUtils.getField(mongoDbFactory, "databaseName").toString(), is("myDatabase"));
}
private void rejectsDatabaseName(String databaseName) {
try {

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:db-factory uri="mongodb://username:password@localhost/database" username="username" />
</beans>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<mongo:db-factory uri="mongodb://username:password@localhost/database" />
</beans>