diff --git a/spring-boot-cli/src/main/content/legal/open_source_licenses.txt b/spring-boot-cli/src/main/content/legal/open_source_licenses.txt index efad7db1c9..552c6c073d 100644 --- a/spring-boot-cli/src/main/content/legal/open_source_licenses.txt +++ b/spring-boot-cli/src/main/content/legal/open_source_licenses.txt @@ -1,18 +1,19 @@ -open_source_license.txt +open_source_licenses.txt Spring Boot CLI - ================================================================== -GoPivotal makes available all content in this download ("Content"). +Pivotal makes available all content in this download ("Content"). Unless otherwise indicated below, the Content is provided to you under -the terms and conditions of the Eclipse Public License Version 1.0 ("EPL"). -A copy of the EPL is available in the file called license.txt. For -purposes of the EPL, "Program" will mean the Content. +the terms and conditions of the Apache License 2.0 (the "License"). A +copy of the license is available in the file called LICENSE.txt or you + may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 The following copyright statements and licenses apply to various open source software packages (or portions thereof) that are distributed with -this Content. +this content. ================================================================= @@ -28,16 +29,43 @@ associated with each component. SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES - >>> antlr:antlr:2.7.7 - >>> net.sf.jopt-simple:jopt-simple:4.5 - >>> org.ow2.asm:asm:4.1 - + >>> JLine (jline:jline) + >>> JOpt Simple (net.sf.jopt-simple:jopt-simple) + >>> ASM 4.0 (org.ow2.asm:asm) SECTION 2: Apache License, V2.0 - >>> org.codehaus.groovy:groovy:2.1 - >>> org.apache.ivy:ivy:2.3.0 + >>> JSON library from Android SDK (com.vaadin.external.google:android-json) + >>> Apache Commons Codec (commons-codec:commons-codec) + >>> Apache HttpClient (org.apache.httpcomponents:httpclient) + >>> Apache HttpCore (org.apache.httpcomponents:httpcore) + >>> Plexus Cipher: encryption/decryption Component (org.sonatype.plexus:plexus-cipher) + >>> Plexus Security Dispatcher Component (org.sonatype.plexus:plexus-sec-dispatcher) + >>> Apache Commons Logging (commons-logging:commons-logging) + >>> Apache Groovy (org.codehaus.groovy:groovy) + >>> Maven Aether Provider (org.apache.maven:maven-aether-provider) + >>> Maven Model (org.apache.maven:maven-model) + >>> Maven Model Builder (org.apache.maven:maven-model-builder) + >>> Maven Repository Metadata Model (org.apache.maven:maven-repository-metadata) + >>> Maven Settings (org.apache.maven:maven-settings) + >>> Maven Settings Builder (org.apache.maven:maven-settings-builder) + >>> Plexus :: Component Annotations (org.codehaus.plexus:plexus-component-annotations) + >>> Plexus Common Utilities (org.codehaus.plexus:plexus-utils) + >>> Plexus Component API (org.codehaus.plexus:plexus-component-api) + >>> Plexus Interpolation API (org.codehaus.plexus:plexus-interpolation) + + +SECTION 3: Eclipse Public License, Version 1.0 + + >>> Aether API (org.eclipse.aether:aether-api) + >>> Aether Connector Basic (org.eclipse.aether:aether-connector-basic) + >>> Aether Implementation (org.eclipse.aether:aether-impl) + >>> Aether SPI (org.eclipse.aether:aether-spi) + >>> Aether Transport File (org.eclipse.aether:aether-transport-file) + >>> Aether Transport HTTP (org.eclipse.aether:aether-transport-http) + >>> Aether Utilities (org.eclipse.aether:aether-util) + --------------- SECTION 1: BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES ---------- @@ -45,38 +73,41 @@ SECTION 2: Apache License, V2.0 BSD-STYLE, MIT-STYLE, OR SIMILAR STYLE LICENSES are applicable to the following component(s). ->>> antlr:antlr:2.7.7 - -SOFTWARE RIGHTS - -ANTLR 1989-2006 Developed by Terence Parr -Partially supported by University of San Francisco & jGuru.com - -We reserve no legal rights to the ANTLR--it is fully in the -public domain. An individual or company may do whatever -they wish with source code distributed with ANTLR or the -code generated by ANTLR, including the incorporation of -ANTLR, or its output, into commerical software. +>>> JLine (jline:jline) -We encourage users to develop software with ANTLR. However, -we do ask that credit is given to us for developing -ANTLR. By "credit", we mean that if you use ANTLR or -incorporate any source code into one of your programs -(commercial product, research project, or otherwise) that -you acknowledge this fact somewhere in the documentation, -research report, etc... If you like ANTLR and have -developed a nice tool with the output, please mention that -you developed it using ANTLR. In addition, we ask that the -headers remain intact in our source code. As long as these -guidelines are kept, we expect to continue enhancing this -system and expect to make other tools available as they are -completed. +Copyright (c) 2002-2006, Marc Prud'hommeaux +All rights reserved. -The primary ANTLR guy: +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with +the distribution. + +Neither the name of JLine nor the names of its contributors +may be used to endorse or promote products derived from this +software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. -Terence Parr -parrt@cs.usfca.edu -parrt@antlr.org >>> net.sf.jopt-simple:jopt-simple:4.5 @@ -103,7 +134,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ->>> org.ow2.asm:asm:4.1 +>>> org.ow2.asm:asm Copyright (c) 2000-2011 INRIA, France Telecom All rights reserved. @@ -136,12 +167,28 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + --------------- SECTION 2: Apache License, V2.0 ---------- Apache License, V2.0 is applicable to the following component(s). ->>> org.codehaus.groovy:groovy:2.1 +>>> org.apache.httpcomponents:httpclient +>>> org.apache.httpcomponents:httpcore +>>> org.sonatype.plexus:plexus-cipher +>>> org.sonatype.plexus:plexus-sec-dispatcher +>>> commons-logging:commons-logging +>>> org.codehaus.groovy:groovy +>>> org.apache.maven:maven-aether-provider +>>> org.apache.maven:maven-model +>>> org.apache.maven:maven-model-builder +>>> org.apache.maven:maven-repository-metadata +>>> org.apache.maven:maven-settings +>>> org.apache.maven:maven-settings-builder +>>> org.codehaus.plexus:plexus-component-annotations +>>> org.codehaus.plexus:plexus-utils +>>> org.codehaus.plexus:plexus-component-api +>>> org.codehaus.plexus:plexus-interpolation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -155,22 +202,58 @@ 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 +>>> CGLIB 3.0 (cglib:cglib:3.0): ->>> org.apache.ivy:ivy:2.3.0 +Per the LICENSE file in the CGLIB JAR distribution downloaded from +http://sourceforge.net/projects/cglib/files/cglib3/3.0/cglib-3.0.jar/download, +CGLIB 3.0 is licensed under the Apache License, version 2.0, the text of which +is included above. -Copyright (c) 2007-2013 The Apache Software Foundation -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 +--------------- SECTION 3: Eclipse Public License, Version 1.0 ---------- -http://www.apache.org/licenses/LICENSE-2.0 +Eclipse Public License, Version 1.0 is applicable to the following component(s). + +>>> org.eclipse.aether:aether-api +>>> org.eclipse.aether:aether-connector-basic +>>> org.eclipse.aether:aether-impl +>>> org.eclipse.aether:aether-spi +>>> org.eclipse.aether:aether-transport-file +>>> org.eclipse.aether:aether-transport-http +>>> org.eclipse.aether:aether-util + +The Eclipse Foundation makes available all content in this plug-in ("Content"). +Unless otherwise indicated below, the Content is provided to you under the terms +and conditions of the Eclipse Public License Version 1.0 ("EPL"). A copy of the +EPL is available at http://www.eclipse.org/legal/epl-v10.html. + +For purposes of the EPL, "Program" will mean the Content. + +If you did not receive this Content directly from the Eclipse Foundation, the +Content is being redistributed by another party ("Redistributor") and different +terms and conditions may apply to your use of any object code in the Content. +Check the Redistributor's license that was provided with the Content. If no such +license exists, contact the Redistributor. Unless otherwise indicated below, the +terms and conditions of the EPL still apply to any source code in the Content and +such source code may be obtained at http://www.eclipse.org/ -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 =========================================================================== + +To the extent any open source subcomponents are licensed under the EPL and/or +other similar licenses that require the source code and/or modifications to +source code to be made available (as would be noted above), you may obtain a +copy of the source code corresponding to the binaries for such open source +components and modifications thereto, if any, (the "Source Files"), by +downloading the Source Files from https://github.com/spring-projects/spring-boot, +or by sending a request, with your name and address to: + + Pivotal, Inc., 875 Howard St, + San Francisco, CA 94103 + United States of America + +or email info@pivotal.io. All such requests should clearly specify: + + OPEN SOURCE FILES REQUEST + Attention General Counsel diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index 2beefb61a7..95c65a4eeb 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1489,11 +1489,10 @@ You can apply the same principle if you are configuring a custom JNDI `DataSourc } ---- - -Spring Boot also provides a utility builder class `DataSourceBuilder` that can be used -to create one of the standard data sources (if it is on the classpath). The builder can -detect the one to use based on the ones available on the classpath and it also auto -detects the driver based on the JDBC url. +Spring Boot also provides a utility builder class `DataSourceBuilder` that can be used to +create one of the standard data sources (if it is on the classpath). The builder can +detect the one to use based on what's available on the classpath. It also auto detects the +driver based on the JDBC url. [source,java,indent=0,subs="verbatim,quotes,attributes"] ---- @@ -1516,7 +1515,7 @@ There is a catch however. Because the actual type of the connection pool is not no keys are generated in the metadata for your custom `DataSource` and no completion is available in your IDE (The `DataSource` interface doesn't expose any property). Also, if you happen to _only_ have Hikari on the classpath, this basic setup will not work because -Hikari has no `url` parameter (but a `jdbcUrl` parameter). You should have to rewrite +Hikari has no `url` parameter (but a `jdbcUrl` parameter). You will have to rewrite your configuration as follows: [source,properties,indent=0] @@ -1618,6 +1617,7 @@ This final example configures two data sources on custom namespaces with the sam than what Spring Boot would do in auto-configuration. + [[howto-use-spring-data-repositories]] === Use Spring Data repositories Spring Data can create implementations for you of `@Repository` interfaces of various diff --git a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/BasicDataSourceExample.java b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/BasicDataSourceExample.java index ad154d89e2..77810befd1 100644 --- a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/BasicDataSourceExample.java +++ b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/BasicDataSourceExample.java @@ -45,4 +45,5 @@ public class BasicDataSourceExample { // end::configuration[] } + } diff --git a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExample.java b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExample.java index b67fe2eca0..a7da853857 100644 --- a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExample.java +++ b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExample.java @@ -25,8 +25,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; /** - * Example configuration for configuring two data sources with what Spring Boot does - * in auto-configuration. + * Example configuration for configuring two data sources with what Spring Boot does in + * auto-configuration. * * @author Stephane Nicoll */ @@ -50,9 +50,7 @@ public class CompleteTwoDataSourcesExample { @Primary @ConfigurationProperties("app.datasource.foo") public DataSource fooDataSource() { - return fooDataSourceProperties() - .initializeDataSourceBuilder() - .build(); + return fooDataSourceProperties().initializeDataSourceBuilder().build(); } @Bean @@ -61,13 +59,10 @@ public class CompleteTwoDataSourcesExample { return new DataSourceProperties(); } - @Bean @ConfigurationProperties("app.datasource.bar") public DataSource barDataSource() { - return barDataSourceProperties() - .initializeDataSourceBuilder() - .build(); + return barDataSourceProperties().initializeDataSourceBuilder().build(); } // end::configuration[] diff --git a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/ConfigurableDataSourceExample.java b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/ConfigurableDataSourceExample.java index 17ce27a2ed..f012b79c67 100644 --- a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/ConfigurableDataSourceExample.java +++ b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/ConfigurableDataSourceExample.java @@ -52,10 +52,10 @@ public class ConfigurableDataSourceExample { @ConfigurationProperties("app.datasource") public HikariDataSource dataSource(DataSourceProperties properties) { return (HikariDataSource) properties.initializeDataSourceBuilder() - .type(HikariDataSource.class) - .build(); + .type(HikariDataSource.class).build(); } // end::configuration[] } + } diff --git a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleDataSourceExample.java b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleDataSourceExample.java index e3e6349199..cfc47471bd 100644 --- a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleDataSourceExample.java +++ b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleDataSourceExample.java @@ -43,8 +43,7 @@ public class SimpleDataSourceExample { @ConfigurationProperties("app.datasource") public HikariDataSource dataSource() { return (HikariDataSource) DataSourceBuilder.create() - .type(HikariDataSource.class) - .build(); + .type(HikariDataSource.class).build(); } // end::configuration[] diff --git a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExample.java b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExample.java index 9f84dd4b11..27d2fc0365 100644 --- a/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExample.java +++ b/spring-boot-docs/src/main/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExample.java @@ -53,18 +53,14 @@ public class SimpleTwoDataSourcesExample { @Primary @ConfigurationProperties("app.datasource.foo") public DataSource fooDataSource() { - return fooDataSourceProperties() - .initializeDataSourceBuilder() - .build(); + return fooDataSourceProperties().initializeDataSourceBuilder().build(); } - @Bean @ConfigurationProperties("app.datasource.bar") public BasicDataSource barDataSource() { return (BasicDataSource) DataSourceBuilder.create() - .type(BasicDataSource.class) - .build(); + .type(BasicDataSource.class).build(); } // end::configuration[] diff --git a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/BasicDataSourceExampleTests.java b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/BasicDataSourceExampleTests.java index 71b4dbff8e..f9507bc7b5 100644 --- a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/BasicDataSourceExampleTests.java +++ b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/BasicDataSourceExampleTests.java @@ -33,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * Test for {@link BasicDataSourceExample}. + * * @author Stephane Nicoll */ @RunWith(SpringRunner.class) diff --git a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExampleTests.java b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExampleTests.java index ba7f261b61..920a224bab 100644 --- a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExampleTests.java +++ b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/CompleteTwoDataSourcesExampleTests.java @@ -47,12 +47,10 @@ public class CompleteTwoDataSourcesExampleTests { @Test public void validateConfiguration() throws SQLException { assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2); - DataSource dataSource = this.context.getBean(DataSource.class); assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource); assertThat(dataSource.getConnection().getMetaData().getURL()) .startsWith("jdbc:h2:mem:"); - DataSource barDataSource = this.context.getBean("barDataSource", DataSource.class); assertThat(barDataSource.getConnection().getMetaData().getURL()) diff --git a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SampleApp.java b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SampleApp.java index 0053272581..786324fe6c 100644 --- a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SampleApp.java +++ b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SampleApp.java @@ -23,8 +23,8 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; /** - * A sample {@link SpringBootConfiguration} that only enables the auto-configuration - * for the {@link DataSource}. + * A sample {@link SpringBootConfiguration} that only enables the auto-configuration for + * the {@link DataSource}. * * @author Stephane Nicoll */ diff --git a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExampleTests.java b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExampleTests.java index 885603d8f3..01ad89b423 100644 --- a/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExampleTests.java +++ b/spring-boot-docs/src/test/java/org/springframework/boot/jdbc/SimpleTwoDataSourcesExampleTests.java @@ -38,8 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Stephane Nicoll */ @RunWith(SpringRunner.class) -@SpringBootTest(properties = { - "app.datasource.bar.url=jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1", +@SpringBootTest(properties = { "app.datasource.bar.url=jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1", "app.datasource.bar.max-total=42" }) @Import(SimpleTwoDataSourcesExample.SimpleDataSourcesConfiguration.class) public class SimpleTwoDataSourcesExampleTests { @@ -50,16 +49,13 @@ public class SimpleTwoDataSourcesExampleTests { @Test public void validateConfiguration() throws SQLException { assertThat(this.context.getBeansOfType(DataSource.class)).hasSize(2); - DataSource dataSource = this.context.getBean(DataSource.class); assertThat(this.context.getBean("fooDataSource")).isSameAs(dataSource); assertThat(dataSource.getConnection().getMetaData().getURL()) .startsWith("jdbc:h2:mem:"); - BasicDataSource barDataSource = this.context.getBean("barDataSource", BasicDataSource.class); - assertThat(barDataSource.getUrl()) - .isEqualTo("jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1"); + assertThat(barDataSource.getUrl()).isEqualTo("jdbc:h2:mem:bar;DB_CLOSE_DELAY=-1"); assertThat(barDataSource.getMaxTotal()).isEqualTo(42); } diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index fb44272b45..601ace544f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -1252,7 +1252,6 @@ public class SpringApplication { finally { close(context); } - } catch (Exception ex) { ex.printStackTrace(); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/config/DelegatingApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/context/config/DelegatingApplicationListener.java index b218d84068..08264ba694 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/config/DelegatingApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/config/DelegatingApplicationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2017 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,6 +17,7 @@ package org.springframework.boot.context.config; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.springframework.beans.BeanUtils; @@ -70,8 +71,11 @@ public class DelegatingApplicationListener @SuppressWarnings("unchecked") private List> getListeners( - ConfigurableEnvironment env) { - String classNames = env.getProperty(PROPERTY_NAME); + ConfigurableEnvironment environment) { + if (environment == null) { + return Collections.emptyList(); + } + String classNames = environment.getProperty(PROPERTY_NAME); List> listeners = new ArrayList>(); if (StringUtils.hasLength(classNames)) { for (String className : StringUtils.commaDelimitedListToSet(classNames)) { diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java index 815f82be77..b3104910f5 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/jetty/JettyEmbeddedServletContainer.java @@ -59,6 +59,8 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer { private Connector[] connectors; + private volatile boolean started; + /** * Create a new {@link JettyEmbeddedServletContainer} instance. * @param server the underlying Jetty server @@ -111,37 +113,43 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer { @Override public void start() throws EmbeddedServletContainerException { - this.server.setConnectors(this.connectors); - if (!this.autoStart) { - return; - } - try { - this.server.start(); - for (Handler handler : this.server.getHandlers()) { - handleDeferredInitialize(handler); + synchronized (this.monitor) { + if (this.started) { + return; + } + this.server.setConnectors(this.connectors); + if (!this.autoStart) { + return; } - Connector[] connectors = this.server.getConnectors(); - for (Connector connector : connectors) { - try { - connector.start(); + try { + this.server.start(); + for (Handler handler : this.server.getHandlers()) { + handleDeferredInitialize(handler); } - catch (BindException ex) { - if (connector instanceof NetworkConnector) { - throw new PortInUseException( - ((NetworkConnector) connector).getPort()); + Connector[] connectors = this.server.getConnectors(); + for (Connector connector : connectors) { + try { + connector.start(); + } + catch (BindException ex) { + if (connector instanceof NetworkConnector) { + throw new PortInUseException( + ((NetworkConnector) connector).getPort()); + } + throw ex; } - throw ex; } + this.started = true; + JettyEmbeddedServletContainer.logger + .info("Jetty started on port(s) " + getActualPortsDescription()); + } + catch (EmbeddedServletContainerException ex) { + throw ex; + } + catch (Exception ex) { + throw new EmbeddedServletContainerException( + "Unable to start embedded Jetty servlet container", ex); } - JettyEmbeddedServletContainer.logger - .info("Jetty started on port(s) " + getActualPortsDescription()); - } - catch (EmbeddedServletContainerException ex) { - throw ex; - } - catch (Exception ex) { - throw new EmbeddedServletContainerException( - "Unable to start embedded Jetty servlet container", ex); } } @@ -197,6 +205,10 @@ public class JettyEmbeddedServletContainer implements EmbeddedServletContainer { @Override public void stop() { synchronized (this.monitor) { + if (!this.started) { + return; + } + this.started = false; try { this.server.stop(); } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java index 93fe10e467..0fe9d6373e 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainer.java @@ -62,6 +62,8 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer private final boolean autoStart; + private volatile boolean started; + /** * Create a new {@link TomcatEmbeddedServletContainer} instance. * @param tomcat the underlying Tomcat server @@ -174,28 +176,34 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer @Override public void start() throws EmbeddedServletContainerException { - try { - addPreviouslyRemovedConnectors(); - Connector connector = this.tomcat.getConnector(); - if (connector != null && this.autoStart) { - startConnector(connector); + synchronized (this.monitor) { + if (this.started) { + return; + } + try { + addPreviouslyRemovedConnectors(); + Connector connector = this.tomcat.getConnector(); + if (connector != null && this.autoStart) { + startConnector(connector); + } + checkThatConnectorsHaveStarted(); + this.started = true; + TomcatEmbeddedServletContainer.logger + .info("Tomcat started on port(s): " + getPortsDescription(true)); + } + catch (ConnectorStartFailedException ex) { + stopSilently(); + throw ex; + } + catch (Exception ex) { + throw new EmbeddedServletContainerException( + "Unable to start embedded Tomcat servlet container", ex); + } + finally { + Context context = findContext(); + ContextBindings.unbindClassLoader(context, context.getNamingToken(), + getClass().getClassLoader()); } - checkThatConnectorsHaveStarted(); - TomcatEmbeddedServletContainer.logger - .info("Tomcat started on port(s): " + getPortsDescription(true)); - } - catch (ConnectorStartFailedException ex) { - stopSilently(); - throw ex; - } - catch (Exception ex) { - throw new EmbeddedServletContainerException( - "Unable to start embedded Tomcat servlet container", ex); - } - finally { - Context context = findContext(); - ContextBindings.unbindClassLoader(context, context.getNamingToken(), - getClass().getClassLoader()); } } @@ -271,7 +279,11 @@ public class TomcatEmbeddedServletContainer implements EmbeddedServletContainer @Override public void stop() throws EmbeddedServletContainerException { synchronized (this.monitor) { + if (!this.started) { + return; + } try { + this.started = false; try { stopTomcat(); this.tomcat.destroy(); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainer.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainer.java index a6d4489a2f..0208cf4080 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/undertow/UndertowEmbeddedServletContainer.java @@ -88,7 +88,7 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine private Undertow undertow; - private boolean started = false; + private volatile boolean started = false; /** * Create a new {@link UndertowEmbeddedServletContainer} instance. @@ -144,6 +144,9 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine @Override public void start() throws EmbeddedServletContainerException { synchronized (this.monitor) { + if (this.started) { + return; + } try { if (!this.autoStart) { return; @@ -305,16 +308,17 @@ public class UndertowEmbeddedServletContainer implements EmbeddedServletContaine @Override public void stop() throws EmbeddedServletContainerException { synchronized (this.monitor) { - if (this.started) { - try { - this.started = false; - this.manager.stop(); - this.undertow.stop(); - } - catch (Exception ex) { - throw new EmbeddedServletContainerException("Unable to stop undertow", - ex); - } + if (!this.started) { + return; + } + this.started = false; + try { + this.manager.stop(); + this.undertow.stop(); + } + catch (Exception ex) { + throw new EmbeddedServletContainerException("Unable to stop undertow", + ex); } } } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java b/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java index 4e2f3d9e4b..695c819d92 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/event/EventPublishingRunListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -16,6 +16,9 @@ package org.springframework.boot.context.event; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationRunListener; import org.springframework.context.ApplicationContextAware; @@ -25,6 +28,7 @@ import org.springframework.context.event.ApplicationEventMulticaster; import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.core.Ordered; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.util.ErrorHandler; /** * {@link SpringApplicationRunListener} to publish {@link SpringApplicationEvent}s. @@ -41,7 +45,7 @@ public class EventPublishingRunListener implements SpringApplicationRunListener, private final String[] args; - private final ApplicationEventMulticaster initialMulticaster; + private final SimpleApplicationEventMulticaster initialMulticaster; public EventPublishingRunListener(SpringApplication application, String[] args) { this.application = application; @@ -89,9 +93,18 @@ public class EventPublishingRunListener implements SpringApplicationRunListener, @Override public void finished(ConfigurableApplicationContext context, Throwable exception) { - // Listeners have been registered to the application context so we should - // use it at this point - context.publishEvent(getFinishedEvent(context, exception)); + SpringApplicationEvent event = getFinishedEvent(context, exception); + if (context != null) { + // Listeners have been registered to the application context so we should + // use it at this point if we can + context.publishEvent(event); + } + else { + if (event instanceof ApplicationFailedEvent) { + this.initialMulticaster.setErrorHandler(new LoggingErrorHandler()); + } + this.initialMulticaster.multicastEvent(event); + } } private SpringApplicationEvent getFinishedEvent( @@ -103,4 +116,15 @@ public class EventPublishingRunListener implements SpringApplicationRunListener, return new ApplicationReadyEvent(this.application, this.args, context); } + private static class LoggingErrorHandler implements ErrorHandler { + + private static Log logger = LogFactory.getLog(EventPublishingRunListener.class); + + @Override + public void handleError(Throwable throwable) { + logger.warn("Error calling ApplicationEventListener", throwable); + } + + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/env/DunnoEnumerablePropertySource.java b/spring-boot/src/main/java/org/springframework/boot/env/DunnoEnumerablePropertySource.java new file mode 100644 index 0000000000..81955e3a76 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/env/DunnoEnumerablePropertySource.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2017 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.env; +/** + * @author pwebb + */ +public interface DunnoEnumerablePropertySource { + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/env/DunnoPropertySource.java b/spring-boot/src/main/java/org/springframework/boot/env/DunnoPropertySource.java new file mode 100644 index 0000000000..628888a107 --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/env/DunnoPropertySource.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2017 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.env; + +/** + * @author pwebb + */ +public interface DunnoPropertySource { + + boolean containsProperty(String name); + + Object getProperty(String name); + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java index dc934324c8..5553b58b9c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/LoggingApplicationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -167,7 +167,7 @@ public class LoggingApplicationListener implements GenericApplicationListener { private static Class[] EVENT_TYPES = { ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, - ContextClosedEvent.class }; + ContextClosedEvent.class, ApplicationFailedEvent.class }; private static Class[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class }; diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java index 41f966cc5d..66b2d59743 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -251,6 +251,7 @@ public class Log4J2LoggingSystem extends Slf4JLoggingSystem { super.cleanUp(); LoggerContext loggerContext = getLoggerContext(); markAsUninitialized(loggerContext); + loggerContext.getConfiguration().removeFilter(FILTER); } private LoggerConfig getLoggerConfig(String name) { diff --git a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java index 28a5d90543..c88a8db80b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java +++ b/spring-boot/src/main/java/org/springframework/boot/logging/logback/LogbackLoggingSystem.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -193,9 +193,11 @@ public class LogbackLoggingSystem extends Slf4JLoggingSystem { @Override public void cleanUp() { - markAsUninitialized(getLoggerContext()); + LoggerContext context = getLoggerContext(); + markAsUninitialized(context); super.cleanUp(); - getLoggerContext().getStatusManager().clear(); + context.getStatusManager().clear(); + context.getTurboFilterList().remove(FILTER); } @Override diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java index 1f8ff21b29..2e60400771 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java @@ -82,6 +82,7 @@ import org.mockito.InOrder; import org.springframework.boot.ApplicationHome; import org.springframework.boot.ApplicationTemp; import org.springframework.boot.context.embedded.Ssl.ClientAuth; +import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.boot.web.servlet.ErrorPage; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletContextInitializer; @@ -124,6 +125,9 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public InternalOutputCapture output = new InternalOutputCapture(); + protected EmbeddedServletContainer container; private final HttpClientContext httpClientContext = HttpClientContext.create(); @@ -157,6 +161,19 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests { assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); } + @Test + public void startCalledTwice() throws Exception { + AbstractEmbeddedServletContainerFactory factory = getFactory(); + this.container = factory + .getEmbeddedServletContainer(exampleServletRegistration()); + this.container.start(); + int port = this.container.getPort(); + this.container.start(); + assertThat(this.container.getPort()).isEqualTo(port); + assertThat(getResponse(getLocalUrl("/hello"))).isEqualTo("Hello World"); + assertThat(this.output.toString()).containsOnlyOnce("started on port"); + } + @Test public void emptyServerWhenPortIsMinusOne() throws Exception { AbstractEmbeddedServletContainerFactory factory = getFactory(); diff --git a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java index 14b28c84a0..64561e9155 100644 --- a/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/logging/LoggingApplicationListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -42,7 +42,10 @@ import org.springframework.boot.context.event.ApplicationFailedEvent; import org.springframework.boot.context.event.ApplicationStartingEvent; import org.springframework.boot.logging.java.JavaLoggingSystem; import org.springframework.boot.testutil.InternalOutputCapture; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.SimpleApplicationEventMulticaster; import org.springframework.context.support.GenericApplicationContext; import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.util.ReflectionTestUtils; @@ -85,8 +88,7 @@ public class LoggingApplicationListenerTests { public void init() throws SecurityException, IOException { LogManager.getLogManager().readConfiguration( JavaLoggingSystem.class.getResourceAsStream("logging.properties")); - this.initializer.onApplicationEvent( - new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); + multicastEvent(new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); new File("target/foo.log").delete(); new File(tmpDir() + "/spring.log").delete(); } @@ -354,8 +356,8 @@ public class LoggingApplicationListenerTests { public void parseArgsDoesntReplace() throws Exception { this.initializer.setSpringBootLogging(LogLevel.ERROR); this.initializer.setParseArgs(false); - this.initializer.onApplicationEvent(new ApplicationStartingEvent( - this.springApplication, new String[] { "--debug" })); + multicastEvent(new ApplicationStartingEvent(this.springApplication, + new String[] { "--debug" })); this.initializer.initialize(this.context.getEnvironment(), this.context.getClassLoader()); this.logger.debug("testatdebug"); @@ -365,7 +367,7 @@ public class LoggingApplicationListenerTests { @Test public void bridgeHandlerLifecycle() throws Exception { assertThat(bridgeHandlerInstalled()).isTrue(); - this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); + multicastEvent(new ContextClosedEvent(this.context)); assertThat(bridgeHandlerInstalled()).isFalse(); } @@ -398,7 +400,7 @@ public class LoggingApplicationListenerTests { TestLoggingApplicationListener listener = new TestLoggingApplicationListener(); System.setProperty(LoggingSystem.class.getName(), TestShutdownHandlerLoggingSystem.class.getName()); - listener.onApplicationEvent( + multicastEvent(listener, new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); assertThat(listener.shutdownHook).isNull(); @@ -411,7 +413,7 @@ public class LoggingApplicationListenerTests { TestShutdownHandlerLoggingSystem.class.getName()); TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, "logging.register_shutdown_hook=true"); - listener.onApplicationEvent( + multicastEvent(listener, new ApplicationStartingEvent(new SpringApplication(), NO_ARGS)); listener.initialize(this.context.getEnvironment(), this.context.getClassLoader()); assertThat(listener.shutdownHook).isNotNull(); @@ -424,12 +426,12 @@ public class LoggingApplicationListenerTests { public void closingContextCleansUpLoggingSystem() { System.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName()); - this.initializer.onApplicationEvent( + multicastEvent( new ApplicationStartingEvent(this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils .getField(this.initializer, "loggingSystem"); assertThat(loggingSystem.cleanedUp).isFalse(); - this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); + multicastEvent(new ContextClosedEvent(this.context)); assertThat(loggingSystem.cleanedUp).isTrue(); } @@ -437,16 +439,16 @@ public class LoggingApplicationListenerTests { public void closingChildContextDoesNotCleanUpLoggingSystem() { System.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName()); - this.initializer.onApplicationEvent( + multicastEvent( new ApplicationStartingEvent(this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils .getField(this.initializer, "loggingSystem"); assertThat(loggingSystem.cleanedUp).isFalse(); GenericApplicationContext childContext = new GenericApplicationContext(); childContext.setParent(this.context); - this.initializer.onApplicationEvent(new ContextClosedEvent(childContext)); + multicastEvent(new ContextClosedEvent(childContext)); assertThat(loggingSystem.cleanedUp).isFalse(); - this.initializer.onApplicationEvent(new ContextClosedEvent(this.context)); + multicastEvent(new ContextClosedEvent(this.context)); assertThat(loggingSystem.cleanedUp).isTrue(); childContext.close(); } @@ -493,17 +495,26 @@ public class LoggingApplicationListenerTests { public void applicationFailedEventCleansUpLoggingSystem() { System.setProperty(LoggingSystem.SYSTEM_PROPERTY, TestCleanupLoggingSystem.class.getName()); - this.initializer.onApplicationEvent( + multicastEvent( new ApplicationStartingEvent(this.springApplication, new String[0])); TestCleanupLoggingSystem loggingSystem = (TestCleanupLoggingSystem) ReflectionTestUtils .getField(this.initializer, "loggingSystem"); assertThat(loggingSystem.cleanedUp).isFalse(); - this.initializer - .onApplicationEvent(new ApplicationFailedEvent(this.springApplication, - new String[0], new GenericApplicationContext(), new Exception())); + multicastEvent(new ApplicationFailedEvent(this.springApplication, new String[0], + new GenericApplicationContext(), new Exception())); assertThat(loggingSystem.cleanedUp).isTrue(); } + private void multicastEvent(ApplicationEvent event) { + multicastEvent(this.initializer, event); + } + + private void multicastEvent(ApplicationListener listener, ApplicationEvent event) { + SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(); + multicaster.addApplicationListener(listener); + multicaster.multicastEvent(event); + } + private boolean bridgeHandlerInstalled() { Logger rootLogger = LogManager.getLogManager().getLogger(""); Handler[] handlers = rootLogger.getHandlers();