Commit f3db8c90 authored by Phillip Webb's avatar Phillip Webb

Merge branch '1.4.x' into 1.5.x

parents 3d619da5 ae910f31
/*
* 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.
......@@ -1208,7 +1208,6 @@ public class SpringApplication {
finally {
close(context);
}
}
catch (Exception ex) {
ex.printStackTrace();
......
/*
* 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<ApplicationListener<ApplicationEvent>> getListeners(
ConfigurableEnvironment env) {
String classNames = env.getProperty(PROPERTY_NAME);
ConfigurableEnvironment environment) {
if (environment == null) {
return Collections.emptyList();
}
String classNames = environment.getProperty(PROPERTY_NAME);
List<ApplicationListener<ApplicationEvent>> listeners = new ArrayList<ApplicationListener<ApplicationEvent>>();
if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.commaDelimitedListToSet(classNames)) {
......
......@@ -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();
}
......
......@@ -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, getNamingToken(context),
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, getNamingToken(context),
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();
......
......@@ -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);
}
}
}
......
/*
* 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);
}
}
}
/*
* 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 };
......
/*
* 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) {
......
/*
* 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
......
......@@ -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();
......
/*
* 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();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment