DATADOC-88 - Create MongoDbFactory to consolidate DB, Server location, and user credentials into one location

DATADOC-147 - Update reference documentation to cover changes from M2 to M3 (partial work)
This commit is contained in:
Mark Pollack
2011-05-24 22:09:12 -04:00
parent e1f8eee2d1
commit fb39f01f25
6 changed files with 168 additions and 70 deletions

View File

@@ -56,11 +56,5 @@ public class SimpleMongoDbFactory implements MongoDbFactory {
Assert.hasText(dbName, "Database name must not be empty");
return MongoDbUtils.getDB(mongo, dbName, username, password == null ? null : password.toCharArray());
}
public Mongo getMongo() {
return this.mongo;
}
}

View File

@@ -23,14 +23,12 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
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.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.document.mongodb.MongoFactoryBean;
import org.springframework.data.document.mongodb.SimpleMongoDbFactory;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
@@ -49,7 +47,6 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionRegistry registry = parserContext.getRegistry();
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
// UserCredentials
@@ -83,46 +80,22 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
dbname = "db";
}
// com.mongodb.Mongo object
String mongoRef = element.getAttribute("mongo-ref");
String mongoId = null;
if (!StringUtils.hasText(mongoRef)) {
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
Element mongoEl = DomUtils.getChildElementByTagName(element, "mongo");
if (null != mongoEl) {
String overrideHost = mongoEl.getAttribute("host");
mongoBuilder.addPropertyValue("host", (StringUtils.hasText(overrideHost) ? overrideHost : host));
String overridePort = mongoEl.getAttribute("port");
mongoBuilder.addPropertyValue("port", (StringUtils.hasText(overridePort) ? overridePort : port));
ParsingUtils.parseMongoOptions(parserContext, mongoEl, mongoBuilder);
ParsingUtils.parseReplicaSet(parserContext, mongoEl, mongoBuilder);
String innerId = mongoEl.getAttribute("id");
if (StringUtils.hasText(innerId)) {
mongoId = innerId;
}
}
else {
mongoBuilder.addPropertyValue("host", host);
mongoBuilder.addPropertyValue("port", port);
}
/* MLP - WIP
if (mongoId == null) {
mongoRef = BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(), parserContext.getRegistry());
} else {
registry.registerBeanDefinition(MONGO, mongoBuilder.getBeanDefinition());
mongoRef = MONGO;
}
*/
registry.registerBeanDefinition(MONGO, mongoBuilder.getBeanDefinition());
mongoRef = MONGO;
}
if (!StringUtils.hasText(mongoRef)) {
//Create implicit com.mongodb.Mongo object and register under generated name
BeanDefinitionBuilder mongoBuilder = BeanDefinitionBuilder.genericBeanDefinition(MongoFactoryBean.class);
mongoBuilder.addPropertyValue("host", host);
mongoBuilder.addPropertyValue("port", port);
mongoRef = BeanDefinitionReaderUtils.registerWithGeneratedName(mongoBuilder.getBeanDefinition(), parserContext.getRegistry());
}
dbFactoryBuilder.addConstructorArgValue(new RuntimeBeanReference(mongoRef));
dbFactoryBuilder.addConstructorArgValue(dbname);
dbFactoryBuilder.addConstructorArgValue(userCredentialsBuilder.getBeanDefinition());
return dbFactoryBuilder.getRawBeanDefinition();
}
}
}

View File

@@ -39,6 +39,7 @@ Defines a MongoDbFactory for connecting to a specific database
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<!--
<xsd:sequence minOccurs="0" maxOccurs="1">
<xsd:element name="mongo" type="mongoType">
<xsd:annotation>
@@ -48,6 +49,7 @@ Defines a Mongo instance used for accessing MongoDB'.
</xsd:annotation>
</xsd:element>
</xsd:sequence>
-->
<xsd:attribute name="id" type="xsd:ID" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[

View File

@@ -22,6 +22,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.document.mongodb.MongoDbFactory;
import org.springframework.data.document.mongodb.MongoFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -54,6 +55,17 @@ public class MongoNamespaceTests extends NamespaceTestSupport {
assertEquals(new Integer(27017), port);
}
@Test
public void testSecondMongoDbFactory() throws Exception {
assertTrue(ctx.containsBean("secondMongoDbFactory"));
MongoDbFactory dbf = (MongoDbFactory) ctx.getBean("secondMongoDbFactory");
Mongo mongo = readField("mongo", dbf);
assertEquals("localhost", mongo.getAddress().getHost());
assertEquals(27017, mongo.getAddress().getPort());
assertEquals("joe", readField("username", dbf));
assertEquals("secret", readField("password", dbf));
assertEquals("database", readField("databaseName", dbf));
}
@Test
public void testMongoSingletonWithPropertyPlaceHolders() throws Exception {
assertTrue(ctx.containsBean("mongo"));

View File

@@ -10,8 +10,7 @@
<context:property-placeholder
location="classpath:/org/springframework/data/document/mongodb/config/mongo.properties"/>
<mongo:db-factory dbname="database" >
<mongo:mongo host="${mongo.host}" port="${mongo.port}">
<mongo:mongo host="${mongo.host}" port="${mongo.port}">
<mongo:options
connections-per-host="${mongo.connectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
@@ -24,8 +23,18 @@
write-number="1"
write-timeout="0"
write-fsync="true"/>
</mongo:mongo>
</mongo:db-factory>
</mongo:mongo>
<mongo:db-factory dbname="database" mongo-ref="mongo"/>
<mongo:db-factory id="secondMongoDbFactory"
host="localhost"
port="27017"
dbname="database"
username="joe"
password="secret"/>
<mongo:mongo id="defaultMongo" host="localhost" port="27017"/>
@@ -46,5 +55,9 @@
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
</bean>
<bean id="anotherMongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
</bean>
</beans>

View File

@@ -77,7 +77,7 @@
the base MongoDB Java driver so you can easily map your existing knowledge
onto the Spring APIs.</para>
<section id="mongodb-requirements">
<section id="mongodb-getting-started">
<title>Getting Started</title>
<para>Spring MongoDB support requires MongoDB 1.4 or higher and Java SE 5
@@ -470,17 +470,16 @@ public class AppConfig {
</section>
<section>
<title>Registering a MongoDbFactory instance using Java based
metadata</title>
<title>The MongoDbFactory interface</title>
<para>As an alternative to configuring a
<classname>com.mongodb.Mongo</classname> instance and later providing
the database name and optionally the username and password, is to use
<classname>SimpleMongoDbFactory</classname>, which implements the
<interfacename>MongoDbFactory</interfacename> inteface shown below. A
reference to <interfacename>MongoDbFactory</interfacename> can be passed
to constructors of <classname>MongoTemplate</classname> to simplify its
creation.</para>
<para>While com.mongodb.Mongo is the entry point to the MongoDB driver
API, connecting to a specific MongoDB database instance requires
additional information such as the database name and an optional
username and password. With that information you can obtain a
com.mongodb.DB object and access all the functionality of a specific
MongoDB database instance. Spring provides the
<classname>org.springframework.data.document.mongodb.MongoDbFactory</classname>
interface shown below to bootstrap connectivity to the database.</para>
<programlisting language="java">public interface MongoDbFactory {
@@ -490,9 +489,55 @@ public class AppConfig {
}</programlisting>
<para>The most simple usage is shown below</para>
<para>The following sections show how you can use the contiainer with
either Java or the XML based metadata to configure an instance of the
<classname>MongoDbFactory</classname> interface. In turn, you can use
the <classname>MongoDbFactory</classname> instance to configure
MongoTemplate.</para>
<programlisting>@Configuration
<para>The class
<classname>org.springframework.data.document.mongodb.SimpleMongoDbFactory</classname>
provides implements the MongoDbFactory interface and is created with a
standard <classname>com.mongodb.Mongo</classname> instance, the database
name and an optional
<classname>org.springframework.data.authentication.UserCredentials</classname>
constructor argument.</para>
<para>Instead of using the IoC container to create an instance of
MongoTemplate, you can just use them in standard Java code as shown
below.</para>
<programlisting language="java">public class MongoApp {
private static final Log log = LogFactory.getLog(MongoApp.class);
public static void main(String[] args) throws Exception {
MongoOperations mongoOps = new MongoTemplate(<emphasis role="bold">new SimpleMongoDbFactory(new Mongo(), "database")</emphasis>);
mongoOps.insert(new Person("Joe", 34));
log.info(mongoOps.findOne(new Query(where("name").is("Joe")), Person.class));
mongoOps.dropCollection("person");
}
}</programlisting>
<para>The code in bold highlights the use of SimpleMongoDbFactory and is
the only difference between the listing shown in the <link lang=""
linkend="mongodb-getting-started" os="">getting started
section</link>.</para>
</section>
<section>
<title>Registering a MongoDbFactory instance using Java based
metadata</title>
<para>To register a MongoDbFactory instance with the container, you
write code much like what was highlighted in the previous code listing.
A simple example is shown below</para>
<programlisting language="java">@Configuration
public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
@@ -502,29 +547,88 @@ public class MongoConfiguration {
}</programlisting>
<para>To define the username and password create an instance of
org.springframework.data.authentication.UserCredentials and pass it into
the constructor as shown below</para>
<classname>org.springframework.data.authentication.UserCredentials</classname>
and pass it into the constructor as shown below. This listing also shows
using <classname>MongoDbFactory</classname> register an instance of
MongoTemplate with the container.</para>
<programlisting>@Configuration
<programlisting language="java">@Configuration
public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
UserCredentials userCredentials = new UserCredentials("joe", "secret");
return new SimpleMongoDbFactory(new Mongo(), "database", userCredentials);
}
public @Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}
</programlisting>
<para></para>
</section>
<section>
<title>Registering a Mongo instance using XML based metadata</title>
<title>Registering a MongoDbFactory instance using XML based
metadata</title>
<para>The mongo namespace lets you create a MongoDbFactory instance
which is a convenient way to group together the a mongo instance, a
database name and an optional username and password. A simple usage is
shown below</para>
<para>The mongo namespace provides a convient way to create a
<classname>SimpleMongoDbFactory</classname> as compared to using
the<literal>&lt;beans/&gt;</literal> namespace. Simple usage is shown
below</para>
<programlisting language="xml"> &lt;mongo:db-factory dbname="database" &gt;</programlisting>
<programlisting language="xml">&lt;mongo:db-factory dbname="database"&gt;</programlisting>
<para>In the above example a <classname>com.mongodb.Mongo</classname>
instance is created using the default host and port number. The
<classname>SimpleMongoDbFactory</classname> registered with the
container is identified by the id 'mongoDbFactory' unless a value for
the id attribute is specified.</para>
<para>You can also provide the host and port for the underlying
com.mongodb.Mongo instance as shown below, in addition to username and
password for the database.</para>
<programlisting language="xml">&lt;mongo:db-factory id="anotherMongoDbFactory"
host="localhost"
port="27017"
dbname="database"
username="joe"
password="secret"/&gt;</programlisting>
<para>If you need to configure additional options on the
<classname>com.mongodb.Mongo</classname> instance that is used to create
a <classname>SimpleMongoDbFactory</classname> you can refer to an
existing bean using the <literal>mongo-ref</literal> attribute as shown
below. To show another common usage pattern, this listing show the use
of a property placeholder to parameterise the configuration and creating
<classname>MongoTemplate</classname>.</para>
<programlisting language="xml">&lt;context:property-placeholder location="classpath:/com/myapp/mongodb/config/mongo.properties"/&gt;
&lt;mongo:mongo host="${mongo.host}" port="${mongo.port}"&gt;
&lt;mongo:options
connections-per-host="${mongo.connectionsPerHost}"
threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
connect-timeout="${mongo.connectTimeout}"
max-wait-time="${mongo.maxWaitTime}"
auto-connect-retry="${mongo.autoConnectRetry}"
socket-keep-alive="${mongo.socketKeepAlive}"
socket-timeout="${mongo.socketTimeout}"
slave-ok="${mongo.slaveOk}"
write-number="1"
write-timeout="0"
write-fsync="true"/&gt;
&lt;/mongo:mongo&gt;
&lt;mongo:db-factory dbname="database" mongo-ref="mongo"/&gt;
&lt;bean id="anotherMongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate"&gt;
&lt;constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/&gt;
&lt;/bean&gt;</programlisting>
<para> </para>
</section>
</section>