From 309f8484a78e9886bbcad944ff6ac07f9748225d Mon Sep 17 00:00:00 2001 From: cjstehno Date: Sun, 20 Mar 2016 08:10:38 -0500 Subject: [PATCH] Fix remote shell to support custom banners Update the remote shell to use the `Banner` interface when possible. Fixes gh-3988 Closes gh-5453 --- .../src/main/resources/banner.txt | 8 ++++++ .../resources/commands/crash/login.groovy | 19 ++++++++++++- .../boot/SpringApplicationBannerPrinter.java | 28 +++++++++++++++++-- .../org/springframework/boot/BannerTests.java | 28 +++++++++++++++++-- 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/banner.txt diff --git a/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/banner.txt b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/banner.txt new file mode 100644 index 0000000000..4ec534531b --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator-noweb/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + ,--. ,--. + \ /-~-\ / + )' a a `( + ( ,---. ) + `(_o_o_)' + )`-'( + +Spring Boot${spring-boot.formatted-version} diff --git a/spring-boot-starters/spring-boot-starter-remote-shell/src/main/resources/commands/crash/login.groovy b/spring-boot-starters/spring-boot-starter-remote-shell/src/main/resources/commands/crash/login.groovy index 7563045ee5..465bd4a012 100644 --- a/spring-boot-starters/spring-boot-starter-remote-shell/src/main/resources/commands/crash/login.groovy +++ b/spring-boot-starters/spring-boot-starter-remote-shell/src/main/resources/commands/crash/login.groovy @@ -1,8 +1,25 @@ welcome = { -> - if (!crash.context.attributes['spring.environment'].getProperty("spring.main.show_banner", Boolean.class, Boolean.TRUE)) { + + def environment = crash.context.attributes['spring.environment'] + def propertyResolver = new org.springframework.boot.bind.RelaxedPropertyResolver(environment, "spring.main."); + def beanFactory = crash.context.attributes['spring.beanfactory'] + + if (!propertyResolver.getProperty("show-banner", Boolean.class, Boolean.TRUE)) { return "" } + // Try to print using the banner interface + if (beanFactory != null) { + try { + def banner = beanFactory.getBean("springBootBanner") + def out = new java.io.ByteArrayOutputStream() + banner.printBanner(environment, null, new java.io.PrintStream(out)) + return out.toString() + } catch (Exception ex) { + // Ignore + } + } + // Resolve hostname def hostName; try { diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java b/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java index d702031430..cea4d5f314 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplicationBannerPrinter.java @@ -63,13 +63,13 @@ class SpringApplicationBannerPrinter { catch (UnsupportedEncodingException ex) { logger.warn("Failed to create String for banner", ex); } - return banner; + return new PrintedBanner(banner, sourceClass); } public Banner print(Environment environment, Class sourceClass, PrintStream out) { Banner banner = getBanner(environment, this.fallbackBanner); banner.printBanner(environment, sourceClass, out); - return banner; + return new PrintedBanner(banner, sourceClass); } private Banner getBanner(Environment environment, Banner definedBanner) { @@ -145,4 +145,28 @@ class SpringApplicationBannerPrinter { } + /** + * Decorator that allows a {@link Banner} to be printed again without needing to + * specify the source class. + */ + private static class PrintedBanner implements Banner { + + private final Banner banner; + + private final Class sourceClass; + + PrintedBanner(Banner banner, Class sourceClass) { + this.banner = banner; + this.sourceClass = sourceClass; + } + + @Override + public void printBanner(Environment environment, Class sourceClass, + PrintStream out) { + sourceClass = (sourceClass == null ? this.sourceClass : sourceClass); + this.banner.printBanner(environment, sourceClass, out); + } + + } + } 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 bea69bc190..defaf6a790 100644 --- a/spring-boot/src/test/java/org/springframework/boot/BannerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/BannerTests.java @@ -21,14 +21,24 @@ import java.io.PrintStream; import org.junit.After; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.runners.MockitoJUnitRunner; import org.springframework.boot.Banner.Mode; import org.springframework.boot.testutil.InternalOutputCapture; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; /** * Tests for {@link Banner} and its usage by {@link SpringApplication}. @@ -37,6 +47,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Michael Stummvoll * @author Michael Simons */ +@RunWith(MockitoJUnitRunner.class) public class BannerTests { private ConfigurableApplicationContext context; @@ -51,6 +62,9 @@ public class BannerTests { @Rule public InternalOutputCapture out = new InternalOutputCapture(); + @Captor + private ArgumentCaptor> sourceClassCaptor; + @Test public void testDefaultBanner() throws Exception { SpringApplication application = new SpringApplication(Config.class); @@ -88,10 +102,18 @@ public class BannerTests { public void testCustomBannerInContext() throws Exception { SpringApplication application = new SpringApplication(Config.class); application.setWebEnvironment(false); - final DummyBanner dummyBanner = new DummyBanner(); - application.setBanner(dummyBanner); + Banner banner = mock(Banner.class); + application.setBanner(banner); this.context = application.run(); - assertThat(this.context.getBean("springBootBanner")).isEqualTo(dummyBanner); + Banner printedBanner = (Banner) this.context.getBean("springBootBanner"); + assertThat(ReflectionTestUtils.getField(printedBanner, "banner")) + .isEqualTo(banner); + verify(banner).printBanner(any(Environment.class), + this.sourceClassCaptor.capture(), any(PrintStream.class)); + reset(banner); + printedBanner.printBanner(this.context.getEnvironment(), null, System.out); + verify(banner).printBanner(any(Environment.class), + eq(this.sourceClassCaptor.getValue()), any(PrintStream.class)); } @Test