From b5b68896013d2594e89b1740643a660ca8b1b583 Mon Sep 17 00:00:00 2001 From: michael Date: Thu, 20 Dec 2018 10:59:02 +0100 Subject: [PATCH 1/2] Allow easy customization of EmbeddedMongo DownloadConfig See gh-15496 --- .../EmbeddedMongoAutoConfiguration.java | 47 ++++++++++++++----- ...dMongoDownloadConfigBuilderCustomizer.java | 38 +++++++++++++++ .../EmbeddedMongoAutoConfigurationTests.java | 38 +++++++++++++++ 3 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index afc8d0f4ed..66bed00bdb 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -39,6 +39,7 @@ import de.flapdoodle.embed.mongo.distribution.Version; import de.flapdoodle.embed.mongo.distribution.Versions; import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.io.ProcessOutput; +import de.flapdoodle.embed.process.config.store.IDownloadConfig; import de.flapdoodle.embed.process.distribution.GenericVersion; import de.flapdoodle.embed.process.io.Processors; import de.flapdoodle.embed.process.io.Slf4jLevel; @@ -48,6 +49,7 @@ import de.flapdoodle.embed.process.store.ArtifactStoreBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -202,24 +204,43 @@ public class EmbeddedMongoAutoConfiguration { @ConditionalOnMissingBean(IRuntimeConfig.class) static class RuntimeConfigConfiguration { + private static Logger EMBEDDED_MONGO_LOGGER = LoggerFactory + .getLogger(RuntimeConfigConfiguration.class.getPackage().getName() + + ".EmbeddedMongo"); + @Bean - public IRuntimeConfig embeddedMongoRuntimeConfig() { - Logger logger = LoggerFactory - .getLogger(getClass().getPackage().getName() + ".EmbeddedMongo"); + public IRuntimeConfig embeddedMongoRuntimeConfig( + IDownloadConfig embeddedMongoDownloadConfig) { ProcessOutput processOutput = new ProcessOutput( - Processors.logTo(logger, Slf4jLevel.INFO), - Processors.logTo(logger, Slf4jLevel.ERROR), Processors.named( - "[console>]", Processors.logTo(logger, Slf4jLevel.DEBUG))); - return new RuntimeConfigBuilder().defaultsWithLogger(Command.MongoD, logger) - .processOutput(processOutput).artifactStore(getArtifactStore(logger)) - .build(); + Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.INFO), + Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.ERROR), + Processors.named("[console>]", + Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.DEBUG))); + return new RuntimeConfigBuilder() + .defaultsWithLogger(Command.MongoD, EMBEDDED_MONGO_LOGGER) + .processOutput(processOutput) + .artifactStore(getArtifactStore(embeddedMongoDownloadConfig)).build(); + } + + @Bean + @ConditionalOnMissingBean + public IDownloadConfig embeddedMongoDownloadConfig( + ObjectProvider downloadConfigBuilderCustomizer) { + DownloadConfigBuilder downloadConfigBuilder = new DownloadConfigBuilder() + .defaultsForCommand(Command.MongoD); + + downloadConfigBuilder + .progressListener(new Slf4jProgressListener(EMBEDDED_MONGO_LOGGER)); + + downloadConfigBuilderCustomizer.stream() + .forEach((c) -> c.customize(downloadConfigBuilder)); + + return downloadConfigBuilder.build(); } - private ArtifactStoreBuilder getArtifactStore(Logger logger) { + private ArtifactStoreBuilder getArtifactStore(IDownloadConfig downloadConfig) { return new ExtractedArtifactStoreBuilder().defaults(Command.MongoD) - .download(new DownloadConfigBuilder() - .defaultsForCommand(Command.MongoD) - .progressListener(new Slf4jProgressListener(logger)).build()); + .download(downloadConfig); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java new file mode 100644 index 0000000000..2211dede5a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2018 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.boot.autoconfigure.mongo.embedded; + +import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder; + +/** + * Callback interface that can be implemented by beans wishing to customize the + * EmbeddedMongo {@link DownloadConfigBuilder} outcome whilst retaining default + * auto-configuration. + * + * @author Michael Gmeiner + * @since 2.2.0 + */ +@FunctionalInterface +public interface EmbeddedMongoDownloadConfigBuilderCustomizer { + + /** + * Customize the {@link DownloadConfigBuilder}. + * @param downloadConfigBuilder the {@link DownloadConfigBuilder} to customize + */ + void customize(DownloadConfigBuilder downloadConfigBuilder); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index bb73d99013..d17fa4b04b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -22,10 +22,13 @@ import java.util.EnumSet; import java.util.stream.Collectors; import com.mongodb.MongoClient; +import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder; import de.flapdoodle.embed.mongo.config.IMongodConfig; import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.config.store.IDownloadConfig; +import de.flapdoodle.embed.process.io.progress.Slf4jProgressListener; import org.bson.Document; import org.junit.After; import org.junit.Rule; @@ -180,6 +183,30 @@ public class EmbeddedMongoAutoConfigurationTests { .isEqualTo("testing"); } + @Test + public void defaultDownloadConfiguration() { + load(); + IDownloadConfig downloadConfig = this.context.getBean(IDownloadConfig.class); + + assertThat(downloadConfig.getDownloadPath().getClass().getSimpleName()) + .isEqualTo("PlatformDependentDownloadPath"); + assertThat(downloadConfig.getUserAgent()).isEqualTo( + "Mozilla/5.0 (compatible; Embedded MongoDB; +https://github.com/flapdoodle-oss/embedmongo.flapdoodle.de)"); + assertThat(downloadConfig.getProgressListener()) + .isInstanceOf(Slf4jProgressListener.class); + } + + @Test + public void customizedDownloadConfiguration() { + load(TestEmbeddedMongoDownloadConfigBuilderCustomizer.class); + + IDownloadConfig downloadConfig = this.context.getBean(IDownloadConfig.class); + assertThat(downloadConfig.getDownloadPath().getPath(null)).isEqualTo("test"); + assertThat(downloadConfig.getUserAgent()).isEqualTo("Test User Agent"); + assertThat(downloadConfig.getProgressListener()) + .isInstanceOf(Slf4jProgressListener.class); + } + private void assertVersionConfiguration(String configuredVersion, String expectedVersion) { this.context = new AnnotationConfigApplicationContext(); @@ -227,4 +254,15 @@ public class EmbeddedMongoAutoConfigurationTests { } + private static class TestEmbeddedMongoDownloadConfigBuilderCustomizer + implements EmbeddedMongoDownloadConfigBuilderCustomizer { + + @Override + public void customize(DownloadConfigBuilder downloadConfigBuilder) { + downloadConfigBuilder.downloadPath("test"); + downloadConfigBuilder.userAgent("Test User Agent"); + } + + } + } From 6ba1f40e595cd18deca470791f354494ac546ada Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 2 Jan 2019 10:33:17 +0100 Subject: [PATCH 2/2] Polish "Allow easy customization of EmbeddedMongo DownloadConfig" Closes gh-15496 --- ...a => DownloadConfigBuilderCustomizer.java} | 7 +-- .../EmbeddedMongoAutoConfiguration.java | 47 +++++++------------ .../EmbeddedMongoAutoConfigurationTests.java | 44 ++++++----------- .../main/asciidoc/spring-boot-features.adoc | 3 +- 4 files changed, 39 insertions(+), 62 deletions(-) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/{EmbeddedMongoDownloadConfigBuilderCustomizer.java => DownloadConfigBuilderCustomizer.java} (80%) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/DownloadConfigBuilderCustomizer.java similarity index 80% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/DownloadConfigBuilderCustomizer.java index 2211dede5a..06c111409e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoDownloadConfigBuilderCustomizer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/DownloadConfigBuilderCustomizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -17,17 +17,18 @@ package org.springframework.boot.autoconfigure.mongo.embedded; import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder; +import de.flapdoodle.embed.process.config.store.IDownloadConfig; /** * Callback interface that can be implemented by beans wishing to customize the - * EmbeddedMongo {@link DownloadConfigBuilder} outcome whilst retaining default + * {@link IDownloadConfig} via a {@link DownloadConfigBuilder} whilst retaining default * auto-configuration. * * @author Michael Gmeiner * @since 2.2.0 */ @FunctionalInterface -public interface EmbeddedMongoDownloadConfigBuilderCustomizer { +public interface DownloadConfigBuilderCustomizer { /** * Customize the {@link DownloadConfigBuilder}. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java index 66bed00bdb..dcb889f8f2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; import com.mongodb.MongoClient; import de.flapdoodle.embed.mongo.Command; @@ -204,41 +205,29 @@ public class EmbeddedMongoAutoConfiguration { @ConditionalOnMissingBean(IRuntimeConfig.class) static class RuntimeConfigConfiguration { - private static Logger EMBEDDED_MONGO_LOGGER = LoggerFactory - .getLogger(RuntimeConfigConfiguration.class.getPackage().getName() - + ".EmbeddedMongo"); - @Bean public IRuntimeConfig embeddedMongoRuntimeConfig( - IDownloadConfig embeddedMongoDownloadConfig) { + ObjectProvider downloadConfigBuilderCustomizers) { + Logger logger = LoggerFactory + .getLogger(getClass().getPackage().getName() + ".EmbeddedMongo"); ProcessOutput processOutput = new ProcessOutput( - Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.INFO), - Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.ERROR), - Processors.named("[console>]", - Processors.logTo(EMBEDDED_MONGO_LOGGER, Slf4jLevel.DEBUG))); - return new RuntimeConfigBuilder() - .defaultsWithLogger(Command.MongoD, EMBEDDED_MONGO_LOGGER) - .processOutput(processOutput) - .artifactStore(getArtifactStore(embeddedMongoDownloadConfig)).build(); + Processors.logTo(logger, Slf4jLevel.INFO), + Processors.logTo(logger, Slf4jLevel.ERROR), Processors.named( + "[console>]", Processors.logTo(logger, Slf4jLevel.DEBUG))); + return new RuntimeConfigBuilder().defaultsWithLogger(Command.MongoD, logger) + .processOutput(processOutput).artifactStore(getArtifactStore(logger, + downloadConfigBuilderCustomizers.orderedStream())) + .build(); } - @Bean - @ConditionalOnMissingBean - public IDownloadConfig embeddedMongoDownloadConfig( - ObjectProvider downloadConfigBuilderCustomizer) { + private ArtifactStoreBuilder getArtifactStore(Logger logger, + Stream downloadConfigBuilderCustomizers) { DownloadConfigBuilder downloadConfigBuilder = new DownloadConfigBuilder() .defaultsForCommand(Command.MongoD); - - downloadConfigBuilder - .progressListener(new Slf4jProgressListener(EMBEDDED_MONGO_LOGGER)); - - downloadConfigBuilderCustomizer.stream() - .forEach((c) -> c.customize(downloadConfigBuilder)); - - return downloadConfigBuilder.build(); - } - - private ArtifactStoreBuilder getArtifactStore(IDownloadConfig downloadConfig) { + downloadConfigBuilder.progressListener(new Slf4jProgressListener(logger)); + downloadConfigBuilderCustomizers + .forEach((customizer) -> customizer.customize(downloadConfigBuilder)); + IDownloadConfig downloadConfig = downloadConfigBuilder.build(); return new ExtractedArtifactStoreBuilder().defaults(Command.MongoD) .download(downloadConfig); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java index d17fa4b04b..928f0d2547 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/embedded/EmbeddedMongoAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -22,19 +22,19 @@ import java.util.EnumSet; import java.util.stream.Collectors; import com.mongodb.MongoClient; -import de.flapdoodle.embed.mongo.config.DownloadConfigBuilder; import de.flapdoodle.embed.mongo.config.IMongodConfig; import de.flapdoodle.embed.mongo.config.Storage; import de.flapdoodle.embed.mongo.distribution.Feature; import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.config.IRuntimeConfig; import de.flapdoodle.embed.process.config.store.IDownloadConfig; -import de.flapdoodle.embed.process.io.progress.Slf4jProgressListener; import org.bson.Document; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; @@ -184,27 +184,12 @@ public class EmbeddedMongoAutoConfigurationTests { } @Test - public void defaultDownloadConfiguration() { - load(); - IDownloadConfig downloadConfig = this.context.getBean(IDownloadConfig.class); - - assertThat(downloadConfig.getDownloadPath().getClass().getSimpleName()) - .isEqualTo("PlatformDependentDownloadPath"); - assertThat(downloadConfig.getUserAgent()).isEqualTo( - "Mozilla/5.0 (compatible; Embedded MongoDB; +https://github.com/flapdoodle-oss/embedmongo.flapdoodle.de)"); - assertThat(downloadConfig.getProgressListener()) - .isInstanceOf(Slf4jProgressListener.class); - } - - @Test - public void customizedDownloadConfiguration() { - load(TestEmbeddedMongoDownloadConfigBuilderCustomizer.class); - - IDownloadConfig downloadConfig = this.context.getBean(IDownloadConfig.class); - assertThat(downloadConfig.getDownloadPath().getPath(null)).isEqualTo("test"); + public void customizeDownloadConfiguration() { + load(DownloadConfigBuilderCustomizerConfiguration.class); + IRuntimeConfig runtimeConfig = this.context.getBean(IRuntimeConfig.class); + IDownloadConfig downloadConfig = (IDownloadConfig) new DirectFieldAccessor( + runtimeConfig.getArtifactStore()).getPropertyValue("downloadConfig"); assertThat(downloadConfig.getUserAgent()).isEqualTo("Test User Agent"); - assertThat(downloadConfig.getProgressListener()) - .isInstanceOf(Slf4jProgressListener.class); } private void assertVersionConfiguration(String configuredVersion, @@ -254,13 +239,14 @@ public class EmbeddedMongoAutoConfigurationTests { } - private static class TestEmbeddedMongoDownloadConfigBuilderCustomizer - implements EmbeddedMongoDownloadConfigBuilderCustomizer { + @Configuration + static class DownloadConfigBuilderCustomizerConfiguration { - @Override - public void customize(DownloadConfigBuilder downloadConfigBuilder) { - downloadConfigBuilder.downloadPath("test"); - downloadConfigBuilder.userAgent("Test User Agent"); + @Bean + public DownloadConfigBuilderCustomizer testDownloadConfigBuilderCustomizer() { + return (downloadConfigBuilder) -> { + downloadConfigBuilder.userAgent("Test User Agent"); + }; } } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 5d3059b5e6..5c4335b47d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4292,7 +4292,8 @@ If you have SLF4J on the classpath, the output produced by Mongo is automaticall to a logger named `org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongo`. You can declare your own `IMongodConfig` and `IRuntimeConfig` beans to take control of -the Mongo instance's configuration and logging routing. +the Mongo instance's configuration and logging routing. The download configuration can be +customized by declaring a `DownloadConfigBuilderCustomizer` bean.