diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/Banner.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/Banner.java index 1624982dae..eea8b02ffd 100644 --- a/spring-bootstrap/src/main/java/org/springframework/bootstrap/Banner.java +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/Banner.java @@ -18,6 +18,12 @@ package org.springframework.bootstrap; import java.io.PrintStream; +import org.springframework.bootstrap.ansi.AnsiOutput; + +import static org.springframework.bootstrap.ansi.AnsiElement.DEFAULT; +import static org.springframework.bootstrap.ansi.AnsiElement.FAINT; +import static org.springframework.bootstrap.ansi.AnsiElement.GREEN; + /** * Writes the 'Spring' banner. * @@ -25,7 +31,8 @@ import java.io.PrintStream; */ abstract class Banner { - private static final String[] BANNER = { " . ____ _ __ _ _", + private static final String[] BANNER = { "", + " . ____ _ __ _ _", " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\", " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", @@ -37,14 +44,12 @@ abstract class Banner { * @param printStream the output print stream */ public static void write(PrintStream printStream) { - printStream.println(); for (String line : BANNER) { printStream.println(line); } String version = Banner.class.getPackage().getImplementationVersion(); - printStream.println(" Spring Bootstrap" - + (version == null ? "" : " (v" + version + ")")); + printStream.println(AnsiOutput.toString(GREEN, " Spring Bootstrap", DEFAULT, + FAINT, (version == null ? "" : " (v" + version + ")"))); printStream.println(); } - } diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiElement.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiElement.java new file mode 100644 index 0000000000..6b2846034b --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiElement.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2013 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.bootstrap.ansi; + +/** + * An ANSI encodable element. + * + * @author Phillip Webb + */ +public interface AnsiElement { + + public static final AnsiElement NORMAL = new DefaultAnsiElement("0"); + public static final AnsiElement BOLD = new DefaultAnsiElement("1"); + public static final AnsiElement FAINT = new DefaultAnsiElement("2"); + public static final AnsiElement ITALIC = new DefaultAnsiElement("3"); + public static final AnsiElement UNDERLINE = new DefaultAnsiElement("4"); + + public static final AnsiElement BLACK = new DefaultAnsiElement("30"); + public static final AnsiElement RED = new DefaultAnsiElement("31"); + public static final AnsiElement GREEN = new DefaultAnsiElement("32"); + public static final AnsiElement YELLOW = new DefaultAnsiElement("33"); + public static final AnsiElement BLUE = new DefaultAnsiElement("34"); + public static final AnsiElement MAGENTA = new DefaultAnsiElement("35"); + public static final AnsiElement CYAN_FG = new DefaultAnsiElement("36"); + public static final AnsiElement WHITE = new DefaultAnsiElement("37"); + public static final AnsiElement DEFAULT = new DefaultAnsiElement("39"); + + /** + * @return the ANSI escape code + */ + @Override + public String toString(); + + /** + * Internal default {@link AnsiElement} implementation. + */ + static class DefaultAnsiElement implements AnsiElement { + + private final String code; + + public DefaultAnsiElement(String code) { + this.code = code; + } + + @Override + public String toString() { + return this.code; + } + } + +} diff --git a/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiOutput.java b/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiOutput.java new file mode 100644 index 0000000000..ce544be2b5 --- /dev/null +++ b/spring-bootstrap/src/main/java/org/springframework/bootstrap/ansi/AnsiOutput.java @@ -0,0 +1,123 @@ +/* + * Copyright 2012-2013 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.bootstrap.ansi; + +import org.springframework.util.Assert; + +/** + * Generates ANSI encoded output, automatically attempting to detect if the terminal + * supports ANSI. + * + * @author Phillip Webb + */ +public abstract class AnsiOutput { + + private static final String ENCODE_JOIN = ";"; + + private static Enabled enabled = Enabled.DETECT; + + private static final String OPERATING_SYSTEM_NAME = System.getProperty("os.name") + .toLowerCase(); + + private static final Object ENCODE_START = "\033["; + + private static final Object ENCODE_END = "m"; + + final private static String RESET = "0;" + AnsiElement.DEFAULT; + + /** + * Sets if ANSI output is enabled. + * @param enabled if ANSI is enabled, disabled or detected + */ + public static void setEnabled(Enabled enabled) { + Assert.notNull(enabled, "Enabled must not be null"); + AnsiOutput.enabled = enabled; + } + + /** + * Create a new ANSI string from the specified elements. Any {@link AnsiElement}s will + * be encoded as required. + * @param elements the elements to encode + * @return a string of the encoded elements + */ + public static String toString(Object... elements) { + StringBuilder sb = new StringBuilder(); + if (isEnabled()) { + buildEnabled(sb, elements); + } + else { + buildDisabled(sb, elements); + } + return sb.toString(); + } + + private static void buildEnabled(StringBuilder sb, Object[] elements) { + boolean writingAnsi = false; + boolean containsEncoding = false; + for (Object element : elements) { + if (element instanceof AnsiElement) { + containsEncoding = true; + if (!writingAnsi) { + sb.append(ENCODE_START); + writingAnsi = true; + } + else { + sb.append(ENCODE_JOIN); + } + } + else { + if (writingAnsi) { + sb.append(ENCODE_END); + writingAnsi = false; + } + } + sb.append(element); + } + if (containsEncoding) { + sb.append(writingAnsi ? ENCODE_JOIN : ENCODE_START); + sb.append(RESET); + sb.append(ENCODE_END); + } + } + + private static void buildDisabled(StringBuilder sb, Object[] elements) { + for (Object element : elements) { + if (!(element instanceof AnsiElement) && element != null) { + sb.append(element); + } + } + } + + private static boolean isEnabled() { + if (enabled == Enabled.DETECT) { + return detectIfEnabled(); + } + return enabled == Enabled.ALWAYS; + } + + private static boolean detectIfEnabled() { + if (System.console() == null) { + return false; + } + return !(OPERATING_SYSTEM_NAME.indexOf("win") >= 0); + } + + public static enum Enabled { + DETECT, ALWAYS, NEVER + }; + +} diff --git a/spring-bootstrap/src/test/java/org/springframework/bootstrap/ansi/AnsiOutputTest.java b/spring-bootstrap/src/test/java/org/springframework/bootstrap/ansi/AnsiOutputTest.java new file mode 100644 index 0000000000..7242769933 --- /dev/null +++ b/spring-bootstrap/src/test/java/org/springframework/bootstrap/ansi/AnsiOutputTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2012-2013 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.bootstrap.ansi; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.bootstrap.ansi.AnsiOutput.Enabled; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.springframework.bootstrap.ansi.AnsiElement.BOLD; +import static org.springframework.bootstrap.ansi.AnsiElement.FAINT; +import static org.springframework.bootstrap.ansi.AnsiElement.GREEN; +import static org.springframework.bootstrap.ansi.AnsiElement.NORMAL; +import static org.springframework.bootstrap.ansi.AnsiElement.RED; + +/** + * Tests for {@link AnsiOutput}. + * + * @author Phillip Webb + */ +public class AnsiOutputTest { + + @BeforeClass + public static void enable() { + AnsiOutput.setEnabled(Enabled.ALWAYS); + } + + @AfterClass + public static void reset() { + AnsiOutput.setEnabled(Enabled.DETECT); + } + + @Test + public void encoding() throws Exception { + String encoded = AnsiOutput.toString("A", RED, BOLD, "B", NORMAL, "D", GREEN, + "E", FAINT, "F"); + assertThat(encoded, equalTo("ABDEF")); + } + +} diff --git a/spring-starters/spring-starter/pom.xml b/spring-starters/spring-starter/pom.xml index 14ca37d1d7..e13c6798c2 100644 --- a/spring-starters/spring-starter/pom.xml +++ b/spring-starters/spring-starter/pom.xml @@ -36,11 +36,6 @@ org.slf4j jcl-over-slf4j - - org.slf4j - slf4j-jdk14 - runtime - org.springframework spring-beans