From 6ac85c17597a482288fb76bd03a64b185bbd200e Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Sat, 26 Apr 2014 12:07:11 +0100 Subject: [PATCH] Add username/password and MongoClientOptions to Mongo config The username/password option stil lonly works for a single host (to connect to a cluster I suspect you need to set the URI). Also added a MongoClientOptions (if a bean of that type exists it will be used to populate the options that aren't in the URI). Fixed gh-536 --- .../mongo/MongoAutoConfiguration.java | 6 +- .../mongo/MongoDataAutoConfiguration.java | 20 ++--- .../autoconfigure/mongo/MongoProperties.java | 83 ++++++++++++++++++- .../mongo/MongoAutoConfigurationTests.java | 48 +++++++++-- .../MongoDataAutoConfigurationTests.java | 14 ++++ .../boot/bind/RelaxedDataBinderTests.java | 17 ++++ 6 files changed, 168 insertions(+), 20 deletions(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java index 20bb5ca8b3..1c6329b383 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.mongodb.Mongo; +import com.mongodb.MongoClientOptions; /** * {@link EnableAutoConfiguration Auto-configuration} for Mongo. @@ -45,6 +46,9 @@ public class MongoAutoConfiguration { @Autowired private MongoProperties properties; + @Autowired(required = false) + private MongoClientOptions options; + private Mongo mongo; @PreDestroy @@ -57,7 +61,7 @@ public class MongoAutoConfiguration { @Bean @ConditionalOnMissingBean public Mongo mongo() throws UnknownHostException { - this.mongo = this.properties.createMongoClient(); + this.mongo = this.properties.createMongoClient(this.options); return this.mongo; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfiguration.java index 13033e9308..02da515cc6 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfiguration.java @@ -52,6 +52,13 @@ public class MongoDataAutoConfiguration { @Autowired private MongoProperties properties; + @Bean + @ConditionalOnMissingBean + public MongoDbFactory mongoDbFactory(Mongo mongo) throws Exception { + String db = this.properties.getMongoClientDatabase(); + return new SimpleMongoDbFactory(mongo, db); + } + @Bean @ConditionalOnMissingBean public MongoTemplate mongoTemplate(MongoDbFactory mongoDbFactory) @@ -61,18 +68,11 @@ public class MongoDataAutoConfiguration { @Bean @ConditionalOnMissingBean - public MongoDbFactory mongoDbFactory(Mongo mongo) throws Exception { + public GridFsTemplate gridFsTemplate(Mongo mongo, MongoTemplate mongoTemplate) { String db = StringUtils.hasText(this.properties.getGridFsDatabase()) ? this.properties .getGridFsDatabase() : this.properties.getMongoClientDatabase(); - - return new SimpleMongoDbFactory(mongo, db); - } - - @Bean - @ConditionalOnMissingBean - public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, - MongoTemplate mongoTemplate) { - return new GridFsTemplate(mongoDbFactory, mongoTemplate.getConverter()); + return new GridFsTemplate(new SimpleMongoDbFactory(mongo, db), + mongoTemplate.getConverter()); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoProperties.java index b71bf74abe..bd3b3165ec 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/MongoProperties.java @@ -17,12 +17,18 @@ package org.springframework.boot.autoconfigure.mongo; import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import com.mongodb.DBPort; import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoClientOptions.Builder; import com.mongodb.MongoClientURI; +import com.mongodb.MongoCredential; +import com.mongodb.ServerAddress; /** * Configuration properties for Mongo. @@ -44,6 +50,10 @@ public class MongoProperties { private String gridFsDatabase; + private String username; + + private char[] password; + public String getHost() { return this.host; } @@ -60,6 +70,31 @@ public class MongoProperties { this.database = database; } + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public char[] getPassword() { + return this.password; + } + + public void setPassword(char[] password) { + this.password = password; + } + + public void clearPassword() { + if (this.password == null) { + return; + } + for (int i = 0; i < this.password.length; i++) { + this.password[i] = 0; + } + } + public String getUri() { return this.uri; } @@ -91,11 +126,51 @@ public class MongoProperties { return new MongoClientURI(this.uri).getDatabase(); } - public MongoClient createMongoClient() throws UnknownHostException { - if (this.host != null) { - return new MongoClient(this.host, this.port); + public MongoClient createMongoClient(MongoClientOptions options) + throws UnknownHostException { + try { + if (this.host != null) { + if (options == null) { + options = MongoClientOptions.builder().build(); + } + List credentials = null; + if (this.password != null && this.username != null) { + credentials = Arrays.asList(MongoCredential.createMongoCRCredential( + this.username, getMongoClientDatabase(), this.password)); + } + return new MongoClient(Arrays.asList(new ServerAddress(this.host, + this.port)), credentials, options); + } + // The options and credentials are in the URI + return new MongoClient(new MongoClientURI(this.uri, builder(options))); + } + finally { + clearPassword(); + } + } + + private Builder builder(MongoClientOptions options) { + Builder builder = MongoClientOptions.builder(); + if (options != null) { + builder.alwaysUseMBeans(options.isAlwaysUseMBeans()); + builder.autoConnectRetry(options.isAutoConnectRetry()); + builder.connectionsPerHost(options.getConnectionsPerHost()); + builder.connectTimeout(options.getConnectTimeout()); + builder.cursorFinalizerEnabled(options.isCursorFinalizerEnabled()); + builder.dbDecoderFactory(options.getDbDecoderFactory()); + builder.dbEncoderFactory(options.getDbEncoderFactory()); + builder.description(options.getDescription()); + builder.maxAutoConnectRetryTime(options.getMaxAutoConnectRetryTime()); + builder.maxWaitTime(options.getMaxWaitTime()); + builder.readPreference(options.getReadPreference()); + builder.socketFactory(options.getSocketFactory()); + builder.socketKeepAlive(options.isSocketKeepAlive()); + builder.socketTimeout(options.getSocketTimeout()); + builder.threadsAllowedToBlockForConnectionMultiplier(options + .getThreadsAllowedToBlockForConnectionMultiplier()); + builder.writeConcern(options.getWriteConcern()); } - return new MongoClient(new MongoClientURI(this.uri)); + return builder; } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index 4d1ff76099..9adf7adbd2 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -19,8 +19,13 @@ package org.springframework.boot.autoconfigure.mongo; import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.mongodb.Mongo; +import com.mongodb.MongoClientOptions; import static org.junit.Assert.assertEquals; @@ -41,11 +46,44 @@ public class MongoAutoConfigurationTests { } @Test - public void templateExists() { + public void clientExists() { this.context = new AnnotationConfigApplicationContext( - PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class); - assertEquals(1, this.context.getBeanNamesForType(MongoTemplate.class).length); + PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class); + assertEquals(1, this.context.getBeanNamesForType(Mongo.class).length); + } + + @Test + public void optionsAdded() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.mongodb.host:localhost"); + this.context.register(OptionsConfig.class, + PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class); + this.context.refresh(); + assertEquals(300, this.context.getBean(Mongo.class).getMongoOptions() + .getSocketTimeout()); + } + + @Test + public void optionsAddedButNoHost() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.mongodb.uri:mongodb://localhost/test"); + this.context.register(OptionsConfig.class, + PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class); + this.context.refresh(); + assertEquals(300, this.context.getBean(Mongo.class).getMongoOptions() + .getSocketTimeout()); + } + + @Configuration + protected static class OptionsConfig { + + @Bean + public MongoClientOptions mongoOptions() { + return MongoClientOptions.builder().socketTimeout(300).build(); + } + } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfigurationTests.java index e72d1c9297..1b4078debb 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoDataAutoConfigurationTests.java @@ -19,7 +19,9 @@ package org.springframework.boot.autoconfigure.mongo; import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.gridfs.GridFsTemplate; import static org.junit.Assert.assertEquals; @@ -45,6 +47,18 @@ public class MongoDataAutoConfigurationTests { this.context = new AnnotationConfigApplicationContext( PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class, MongoDataAutoConfiguration.class); + assertEquals(1, this.context.getBeanNamesForType(MongoTemplate.class).length); + } + + @Test + public void gridFsTemplateExists() { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.mongodb.gridFsDatabase:grid"); + this.context.register(PropertyPlaceholderAutoConfiguration.class, + MongoAutoConfiguration.class, MongoDataAutoConfiguration.class); + this.context.refresh(); assertEquals(1, this.context.getBeanNamesForType(GridFsTemplate.class).length); } + } diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java index d87175ee19..939a27d9a1 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/RelaxedDataBinderTests.java @@ -74,6 +74,13 @@ public class RelaxedDataBinderTests { assertEquals("bar", target.getFoo()); } + @Test + public void testBindChars() throws Exception { + VanillaTarget target = new VanillaTarget(); + bind(target, "bar: foo"); + assertEquals("foo", new String(target.getBar())); + } + @Test public void testBindStringWithPrefix() throws Exception { VanillaTarget target = new VanillaTarget(); @@ -656,12 +663,22 @@ public class RelaxedDataBinderTests { private String foo; + private char[] bar; + private int value; private String foo_bar; private String fooBaz; + public char[] getBar() { + return this.bar; + } + + public void setBar(char[] bar) { + this.bar = bar; + } + public int getValue() { return this.value; }