diff --git a/spring-boot/src/main/java/org/springframework/boot/Banner.java b/spring-boot/src/main/java/org/springframework/boot/Banner.java index b95e4b5006f..2b7f6294726 100644 --- a/spring-boot/src/main/java/org/springframework/boot/Banner.java +++ b/spring-boot/src/main/java/org/springframework/boot/Banner.java @@ -32,8 +32,9 @@ public interface Banner { /** * Print the banner to the specified print stream. * @param environment the spring environment + * @param sourceClass the source class for the application * @param out the output print stream */ - void printBanner(Environment environment, PrintStream out); + void printBanner(Environment environment, Class sourceClass, PrintStream out); } diff --git a/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java b/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java new file mode 100644 index 00000000000..594cd9f93ce --- /dev/null +++ b/spring-boot/src/main/java/org/springframework/boot/ResourceBanner.java @@ -0,0 +1,104 @@ +/* + * Copyright 2012-2014 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; + +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.core.env.Environment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertyResolver; +import org.springframework.core.env.PropertySourcesPropertyResolver; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.StreamUtils; + +/** + * Banner implementation that prints from a source {@link Resource}. + * + * @author Phillip Webb + * @since 1.2.0 + */ +public class ResourceBanner implements Banner { + + private static final Log log = LogFactory.getLog(ResourceBanner.class); + + private Resource resource; + + public ResourceBanner(Resource resource) { + Assert.notNull(resource, "Resource must not be null"); + Assert.isTrue(resource.exists(), "Resource must exist"); + this.resource = resource; + } + + @Override + public void printBanner(Environment environment, Class sourceClass, PrintStream out) { + try { + String banner = StreamUtils.copyToString( + this.resource.getInputStream(), + environment.getProperty("banner.charset", Charset.class, + Charset.forName("UTF-8"))); + + for (PropertyResolver resolver : getPropertyResolvers(environment, + sourceClass)) { + banner = resolver.resolvePlaceholders(banner); + } + out.println(banner); + } + catch (Exception ex) { + log.warn("Banner not printable: " + this.resource + " (" + ex.getClass() + + ": '" + ex.getMessage() + "')", ex); + } + } + + protected List getPropertyResolvers(Environment environment, + Class sourceClass) { + List resolvers = new ArrayList(); + resolvers.add(environment); + resolvers.add(getVersionResolver(sourceClass)); + return resolvers; + } + + private PropertyResolver getVersionResolver(Class sourceClass) { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addLast(new MapPropertySource("version", + getVersionsMap(sourceClass))); + return new PropertySourcesPropertyResolver(propertySources); + } + + private Map getVersionsMap(Class sourceClass) { + String applicationVersion = (sourceClass == null ? null : sourceClass + .getPackage().getImplementationVersion()); + String bootVersion = Banner.class.getPackage().getImplementationVersion(); + Map versions = new HashMap(); + versions.put("application.version", getVersionString(applicationVersion)); + versions.put("spring-boot.version", getVersionString(bootVersion)); + return versions; + } + + private String getVersionString(String version) { + return (version == null ? "" : " (v" + version + ")"); + } + +} 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 8ef39f1994f..7dac65f7070 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -17,7 +17,6 @@ package org.springframework.boot; import java.lang.reflect.Constructor; -import java.nio.charset.Charset; import java.security.AccessControlException; import java.util.ArrayList; import java.util.Arrays; @@ -67,7 +66,6 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StopWatch; -import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.WebApplicationContext; @@ -482,32 +480,19 @@ public class SpringApplication { : new DefaultResourceLoader(getClassLoader()); Resource resource = resourceLoader.getResource(location); if (resource.exists()) { - printBannerResource(environment, resource); + new ResourceBanner(resource).printBanner(environment, + this.mainApplicationClass, System.out); return; } if (this.banner != null) { - this.banner.printBanner(environment, System.out); + this.banner.printBanner(environment, this.mainApplicationClass, System.out); return; } printBanner(); } - private void printBannerResource(Environment environment, Resource resource) { - try { - String banner = StreamUtils.copyToString( - resource.getInputStream(), - environment.getProperty("banner.charset", Charset.class, - Charset.forName("UTF-8"))); - System.out.println(environment.resolvePlaceholders(banner)); - } - catch (Exception ex) { - this.log.warn("Banner not printable: " + resource + " (" + ex.getClass() - + ": '" + ex.getMessage() + "')", ex); - } - } - /** * Print a simple banner message to the console. Subclasses can override this method * to provide additional or alternative banners. @@ -517,7 +502,7 @@ public class SpringApplication { */ @Deprecated protected void printBanner() { - DEFAULT_BANNER.printBanner(null, System.out); + DEFAULT_BANNER.printBanner(null, this.mainApplicationClass, System.out); } /** diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java b/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java index 4bd6a1594b1..4c738781135 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringBootBanner.java @@ -45,7 +45,8 @@ class SpringBootBanner implements Banner { private static final int STRAP_LINE_SIZE = 42; @Override - public void printBanner(Environment environment, PrintStream printStream) { + public void printBanner(Environment environment, Class sourceClass, + PrintStream printStream) { for (String line : BANNER) { printStream.println(line); } diff --git a/spring-boot/src/test/java/org/springframework/boot/BannerTests.java b/spring-boot/src/test/java/org/springframework/boot/BannerTests.java index 02a218512e1..0cb00e7927f 100644 --- a/spring-boot/src/test/java/org/springframework/boot/BannerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/BannerTests.java @@ -58,7 +58,8 @@ public class BannerTests { static class DummyBanner implements Banner { @Override - public void printBanner(Environment environment, PrintStream out) { + public void printBanner(Environment environment, Class sourceClass, + PrintStream out) { out.println("My Banner"); } diff --git a/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java b/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java new file mode 100644 index 00000000000..58641018e92 --- /dev/null +++ b/spring-boot/src/test/java/org/springframework/boot/ResourceBannerTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-2014 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; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Collections; +import java.util.Map; + +import org.junit.Test; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; +import org.springframework.mock.env.MockEnvironment; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertThat; + +/** + * Tests for {@link ResourceBanner}. + * + * @author Phillip Webb + */ +public class ResourceBannerTests { + + @Test + public void renderWithReplacement() throws Exception { + Resource resource = new ByteArrayResource( + "banner ${a} ${spring-boot.version} ${application.version}".getBytes()); + ResourceBanner banner = new ResourceBanner(resource); + ConfigurableEnvironment environment = new MockEnvironment(); + Map source = Collections. singletonMap("a", "1"); + environment.getPropertySources().addLast(new MapPropertySource("map", source)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + banner.printBanner(environment, getClass(), new PrintStream(out)); + assertThat(out.toString(), startsWith("banner 1")); + assertThat(out.toString(), not(containsString("$"))); + } + +}