diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java index 95738bac5f..77177b59eb 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/LogFileMvcEndpoint.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.io.File; import java.io.IOException; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -82,7 +83,8 @@ public class LogFileMvcEndpoint extends AbstractNamedMvcEndpoint { } resource = null; } - new Handler(resource).handleRequest(request, response); + Handler handler = new Handler(resource, request.getServletContext()); + handler.handleRequest(request, response); } private Resource getLogFileResource() { @@ -104,10 +106,11 @@ public class LogFileMvcEndpoint extends AbstractNamedMvcEndpoint { private final Resource resource; - Handler(Resource resource) { + Handler(Resource resource, ServletContext servletContext) { this.resource = resource; getLocations().add(resource); try { + setServletContext(servletContext); afterPropertiesSet(); } catch (Exception ex) { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index 538ac5c0a4..67d1ccbd96 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -16,16 +16,12 @@ package org.springframework.boot.autoconfigure.orm.jpa; -import java.net.URL; import java.util.List; import java.util.Map; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -53,7 +49,6 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.jta.JtaTransactionManager; -import org.springframework.util.ResourceUtils; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @@ -69,8 +64,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter @Import(DataSourceInitializedPublisher.Registrar.class) public abstract class JpaBaseConfiguration implements BeanFactoryAware { - private static final Log logger = LogFactory.getLog(JpaBaseConfiguration.class); - private final DataSource dataSource; private final JpaProperties properties; @@ -110,8 +103,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { ObjectProvider persistenceUnitManagerProvider) { EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder( jpaVendorAdapter, this.properties.getProperties(), - persistenceUnitManagerProvider.getIfAvailable(), - determinePersistenceUnitRootLocation()); + persistenceUnitManagerProvider.getIfAvailable()); builder.setCallback(getVendorCallback()); return builder; } @@ -190,19 +182,6 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } - private URL determinePersistenceUnitRootLocation() { - Class source = getClass(); - try { - URL url = source.getProtectionDomain().getCodeSource().getLocation(); - return ResourceUtils.extractJarFileURL(url); - } - catch (Exception ex) { - logger.info("Could not determine persistence " + "unit root location from " - + source + " : " + ex); - } - return null; - } - @Configuration @ConditionalOnWebApplication @ConditionalOnClass(WebMvcConfigurerAdapter.class) diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java index 806a4a637d..3fac71701a 100755 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/env/DevToolsPropertyDefaultsPostProcessor.java @@ -21,10 +21,13 @@ import java.util.HashMap; import java.util.Map; import org.springframework.boot.SpringApplication; +import org.springframework.boot.bind.RelaxedPropertyResolver; +import org.springframework.boot.devtools.restart.Restarter; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.Environment; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; @@ -59,7 +62,7 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro @Override public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { - if (isLocalApplication(environment)) { + if (isLocalApplication(environment) && canAddProperties(environment)) { PropertySource propertySource = new MapPropertySource("refresh", PROPERTIES); environment.getPropertySources().addLast(propertySource); @@ -70,4 +73,24 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro return environment.getPropertySources().get("remoteUrl") == null; } + private boolean canAddProperties(Environment environment) { + return isRestarterInitialized() || isRemoteRestartEnabled(environment); + } + + private boolean isRestarterInitialized() { + try { + Restarter restarter = Restarter.getInstance(); + return (restarter != null && restarter.getInitialUrls() != null); + } + catch (Exception ex) { + return false; + } + } + + private boolean isRemoteRestartEnabled(Environment environment) { + RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment, + "spring.devtools.remote."); + return resolver.containsProperty("secret"); + } + } diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java index 2caae8c0e9..7fa890e272 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/env/DevToolPropertiesIntegrationTests.java @@ -16,11 +16,20 @@ package org.springframework.boot.devtools.env; +import java.net.URL; +import java.util.Collections; + import org.junit.After; +import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.devtools.restart.RestartInitializer; +import org.springframework.boot.devtools.restart.Restarter; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -32,13 +41,22 @@ import org.springframework.context.annotation.Configuration; */ public class DevToolPropertiesIntegrationTests { + @Rule + public ExpectedException thrown = ExpectedException.none(); + private ConfigurableApplicationContext context; + @Before + public void setup() { + Restarter.initialize(new String[] {}, false, new MockInitializer(), false); + } + @After public void cleanup() { if (this.context != null) { this.context.close(); } + Restarter.clearInstance(); } @Test @@ -59,6 +77,33 @@ public class DevToolPropertiesIntegrationTests { this.context.getBean(MyBean.class); } + @Test + public void postProcessWhenRestarterDisabledAndRemoteSecretNotSetShouldNotAddPropertySource() + throws Exception { + Restarter.clearInstance(); + Restarter.disable(); + SpringApplication application = new SpringApplication( + BeanConditionConfiguration.class); + application.setWebEnvironment(false); + this.context = application.run(); + this.thrown.expect(NoSuchBeanDefinitionException.class); + this.context.getBean(MyBean.class); + } + + @Test + public void postProcessWhenRestarterDisabledAndRemoteSecretSetShouldAddPropertySource() + throws Exception { + Restarter.clearInstance(); + Restarter.disable(); + SpringApplication application = new SpringApplication( + BeanConditionConfiguration.class); + application.setWebEnvironment(false); + application.setDefaultProperties(Collections.singletonMap( + "spring.devtools.remote.secret", "donttell")); + this.context = application.run(); + this.context.getBean(MyBean.class); + } + @Configuration @ConditionalOnProperty("spring.h2.console.enabled") static class ClassConditionConfiguration { @@ -79,4 +124,12 @@ public class DevToolPropertiesIntegrationTests { } + static class MockInitializer implements RestartInitializer { + + @Override + public URL[] getInitialUrls(Thread thread) { + return new URL[] {}; + } + + } } diff --git a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java index 33df6947e7..3e018a5c06 100644 --- a/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java +++ b/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/orm/jpa/TestDatabaseAutoConfiguration.java @@ -101,15 +101,20 @@ public class TestDatabaseAutoConfiguration { ConfigurableListableBeanFactory beanFactory) { BeanDefinitionHolder holder = getDataSourceBeanDefinition(beanFactory); if (holder != null) { - logger.info("Replacing '" + holder.getBeanName() - + "' DataSource bean with embedded version"); - registry.registerBeanDefinition(holder.getBeanName(), - createEmbeddedBeanDefinition()); + String beanName = holder.getBeanName(); + boolean primary = holder.getBeanDefinition().isPrimary(); + logger.info("Replacing '" + beanName + "' DataSource bean with " + + (primary ? "primary " : "") + "embedded version"); + registry.registerBeanDefinition(beanName, + createEmbeddedBeanDefinition(primary)); } } - private BeanDefinition createEmbeddedBeanDefinition() { - return new RootBeanDefinition(EmbeddedDataSourceFactoryBean.class); + private BeanDefinition createEmbeddedBeanDefinition(boolean primary) { + BeanDefinition beanDefinition = new RootBeanDefinition( + EmbeddedDataSourceFactoryBean.class); + beanDefinition.setPrimary(primary); + return beanDefinition; } private BeanDefinitionHolder getDataSourceBeanDefinition( diff --git a/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests.java b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests.java new file mode 100644 index 0000000000..5428b5da9c --- /dev/null +++ b/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2016 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.test.autoconfigure.orm.jpa; + +import javax.sql.DataSource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; +import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link AutoConfigureTestDatabase} when there are multiple + * datasources. + * + * @author Greg Potter + */ +@RunWith(SpringRunner.class) +@DataJpaTest +@AutoConfigureTestDatabase +public class AutoConfigureTestDatabaseWithMultipleDatasourcesIntegrationTests { + + @Autowired + private TestEntityManager entities; + + @Autowired + private ExampleRepository repository; + + @Autowired + private DataSource dataSource; + + @Test + public void testRepository() throws Exception { + this.entities.persist(new ExampleEntity("boot", "124")); + this.entities.flush(); + ExampleEntity found = this.repository.findByReference("124"); + assertThat(found.getName()).isEqualTo("boot"); + } + + @Test + public void replacesDefinedDataSourceWithExplicit() throws Exception { + // Look that the datasource is replaced with an H2 DB. + String product = this.dataSource.getConnection().getMetaData() + .getDatabaseProductName(); + assertThat(product).startsWith("H2"); + } + + @Configuration + @EnableAutoConfiguration + static class Config { + + @Bean + @Primary + public DataSource dataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.HSQL); + return builder.build(); + } + + @Bean + public DataSource secondaryDataSource() { + EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder() + .setType(EmbeddedDatabaseType.HSQL); + return builder.build(); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java index 197671b808..24c862c3e7 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/main/java/org/springframework/boot/configurationprocessor/TypeUtils.java @@ -96,8 +96,8 @@ class TypeUtils { /** * Return the qualified name of the specified element. * @param element the element to handle - * @return the fully qualified name of the element, suitable for a call - * to {@link Class#forName(String)} + * @return the fully qualified name of the element, suitable for a call to + * {@link Class#forName(String)} */ public String getQualifiedName(Element element) { if (element == null) { @@ -106,19 +106,20 @@ class TypeUtils { TypeElement enclosingElement = getEnclosingTypeElement(element.asType()); if (enclosingElement != null) { return getQualifiedName(enclosingElement) + "$" - + ((DeclaredType) element.asType()).asElement().getSimpleName().toString(); + + ((DeclaredType) element.asType()).asElement().getSimpleName() + .toString(); } if (element instanceof TypeElement) { return ((TypeElement) element).getQualifiedName().toString(); } - throw new IllegalStateException("Could not extract qualified name from " - + element); + throw new IllegalStateException( + "Could not extract qualified name from " + element); } /** * Return the type of the specified {@link TypeMirror} including all its generic * information. - * @param type the type to handle + * @param type the type to handle * @return a representation of the type including all its generic information */ public String getType(TypeMirror type) { diff --git a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java index 576b94fcac..c9a3033a6e 100644 --- a/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java +++ b/spring-boot-tools/spring-boot-configuration-processor/src/test/java/org/springframework/boot/configurationprocessor/ConfigurationMetadataAnnotationProcessorTests.java @@ -404,8 +404,7 @@ public class ConfigurationMetadataAnnotationProcessorTests { assertThat(metadata).has(Metadata.withGroup("generic.foo.bar.biz").ofType( "org.springframework.boot.configurationsample.specific.GenericConfig$Bar$Biz")); assertThat(metadata).has(Metadata.withProperty("generic.foo.name") - .ofType(String.class) - .fromSource(GenericConfig.Foo.class)); + .ofType(String.class).fromSource(GenericConfig.Foo.class)); assertThat(metadata).has(Metadata.withProperty("generic.foo.string-to-bar") .ofType("java.util.Map>") .fromSource(GenericConfig.Foo.class)); @@ -413,11 +412,9 @@ public class ConfigurationMetadataAnnotationProcessorTests { .ofType("java.util.Map") .fromSource(GenericConfig.Foo.class)); assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.name") - .ofType("java.lang.String") - .fromSource(GenericConfig.Bar.class)); + .ofType("java.lang.String").fromSource(GenericConfig.Bar.class)); assertThat(metadata).has(Metadata.withProperty("generic.foo.bar.biz.name") - .ofType("java.lang.String") - .fromSource(GenericConfig.Bar.Biz.class)); + .ofType("java.lang.String").fromSource(GenericConfig.Bar.Biz.class)); assertThat(metadata.getItems()).hasSize(9); } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java index 7a3ee76a4f..162395c295 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarFile.java @@ -371,6 +371,10 @@ public class JarFile extends java.util.jar.JarFile { return this.pathFromRoot; } + JarFileType getType() { + return this.type; + } + /** * Register a {@literal 'java.protocol.handler.pkgs'} property so that a * {@link URLStreamHandler} will be located to deal with jar URLs. @@ -396,7 +400,10 @@ public class JarFile extends java.util.jar.JarFile { } } - private enum JarFileType { + /** + * The type of a {@link JarFile}. + */ + enum JarFileType { DIRECT, NESTED_DIRECTORY, NESTED_JAR } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java index ca2ff46c16..7f2b5ce6ed 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java @@ -29,6 +29,8 @@ import java.net.URLEncoder; import java.net.URLStreamHandler; import java.security.Permission; +import org.springframework.boot.loader.data.RandomAccessData.ResourceAccess; + /** * {@link java.net.JarURLConnection} used to support {@link JarFile#getUrl()}. * @@ -160,11 +162,14 @@ final class JarURLConnection extends java.net.JarURLConnection { if (this.jarFile == null) { throw FILE_NOT_FOUND_EXCEPTION; } - if (this.jarEntryName.isEmpty()) { + if (this.jarEntryName.isEmpty() + && this.jarFile.getType() == JarFile.JarFileType.DIRECT) { throw new IOException("no entry name specified"); } connect(); - InputStream inputStream = this.jarFile.getInputStream(this.jarEntry); + InputStream inputStream = (this.jarEntryName.isEmpty() + ? this.jarFile.getData().getInputStream(ResourceAccess.ONCE) + : this.jarFile.getInputStream(this.jarEntry)); if (inputStream == null) { throwFileNotFound(this.jarEntryName, this.jarFile); } diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java index f4cc67b9ff..d9e2993400 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/jar/JarFileTests.java @@ -28,6 +28,7 @@ import java.net.URLClassLoader; import java.nio.charset.Charset; import java.util.Enumeration; import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; import java.util.jar.Manifest; import java.util.zip.ZipEntry; @@ -54,6 +55,7 @@ import static org.mockito.Mockito.verify; * @author Andy Wilkinson */ public class JarFileTests { + private static final String PROTOCOL_HANDLER = "java.protocol.handler.pkgs"; private static final String HANDLERS_PACKAGE = "org.springframework.boot.loader"; @@ -270,6 +272,12 @@ public class JarFileTests { assertThat(conn.getJarFile()).isSameAs(nestedJarFile); assertThat(conn.getJarFileURL().toString()) .isEqualTo("jar:" + this.rootJarFile.toURI() + "!/nested.jar"); + assertThat(conn.getInputStream()).isNotNull(); + JarInputStream jarInputStream = new JarInputStream(conn.getInputStream()); + assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("3.dat"); + assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("4.dat"); + assertThat(jarInputStream.getNextJarEntry().getName()).isEqualTo("\u00E4.dat"); + jarInputStream.close(); assertThat(conn.getPermission()).isInstanceOf(FilePermission.class); FilePermission permission = (FilePermission) conn.getPermission(); assertThat(permission.getActions()).isEqualTo("read"); diff --git a/spring-boot/src/main/java/org/springframework/boot/system/ApplicationPidFileWriter.java b/spring-boot/src/main/java/org/springframework/boot/system/ApplicationPidFileWriter.java index 94965061e5..a8ff926b43 100644 --- a/spring-boot/src/main/java/org/springframework/boot/system/ApplicationPidFileWriter.java +++ b/spring-boot/src/main/java/org/springframework/boot/system/ApplicationPidFileWriter.java @@ -30,6 +30,7 @@ import org.springframework.boot.ApplicationPid; import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.SpringApplicationEvent; import org.springframework.context.ApplicationListener; import org.springframework.core.Ordered; @@ -49,7 +50,8 @@ import org.springframework.util.Assert; *

* Note: access to the Spring {@link Environment} is only possible when the * {@link #setTriggerEventType(Class) triggerEventType} is set to - * {@link ApplicationEnvironmentPreparedEvent} or {@link ApplicationPreparedEvent}. + * {@link ApplicationEnvironmentPreparedEvent}, {@link ApplicationReadyEvent}, or + * {@link ApplicationPreparedEvent}. * * @author Jakub Kubrynski * @author Dave Syer @@ -231,6 +233,10 @@ public class ApplicationPidFileWriter return ((ApplicationPreparedEvent) event).getApplicationContext() .getEnvironment(); } + if (event instanceof ApplicationReadyEvent) { + return ((ApplicationReadyEvent) event).getApplicationContext() + .getEnvironment(); + } return null; } diff --git a/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidFileWriterTests.java b/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidFileWriterTests.java index 1e4d0af805..5b6ada3da3 100644 --- a/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidFileWriterTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/system/ApplicationPidFileWriterTests.java @@ -29,6 +29,7 @@ import org.junit.rules.TemporaryFolder; import org.springframework.boot.SpringApplication; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.boot.context.event.SpringApplicationEvent; import org.springframework.context.ConfigurableApplicationContext; @@ -99,7 +100,7 @@ public class ApplicationPidFileWriterTests { } @Test - public void differentEventTypes() throws Exception { + public void tryEnvironmentPreparedEvent() throws Exception { File file = this.temporaryFolder.newFile(); SpringApplicationEvent event = createEnvironmentPreparedEvent("spring.pid.file", file.getAbsolutePath()); @@ -111,6 +112,19 @@ public class ApplicationPidFileWriterTests { assertThat(FileCopyUtils.copyToString(new FileReader(file))).isNotEmpty(); } + @Test + public void tryReadyEvent() throws Exception { + File file = this.temporaryFolder.newFile(); + SpringApplicationEvent event = createReadyEvent("spring.pid.file", + file.getAbsolutePath()); + ApplicationPidFileWriter listener = new ApplicationPidFileWriter(); + listener.onApplicationEvent(event); + assertThat(FileCopyUtils.copyToString(new FileReader(file))).isEmpty(); + listener.setTriggerEventType(ApplicationReadyEvent.class); + listener.onApplicationEvent(event); + assertThat(FileCopyUtils.copyToString(new FileReader(file))).isNotEmpty(); + } + @Test public void withNoEnvironment() throws Exception { File file = this.temporaryFolder.newFile(); @@ -170,6 +184,15 @@ public class ApplicationPidFileWriterTests { context); } + private SpringApplicationEvent createReadyEvent(String propName, String propValue) { + ConfigurableEnvironment environment = createEnvironment(propName, propValue); + ConfigurableApplicationContext context = mock( + ConfigurableApplicationContext.class); + given(context.getEnvironment()).willReturn(environment); + return new ApplicationReadyEvent(new SpringApplication(), new String[] {}, + context); + } + private ConfigurableEnvironment createEnvironment(String propName, String propValue) { MockPropertySource propertySource = mockPropertySource(propName, propValue); ConfigurableEnvironment environment = new StandardEnvironment();