/* * This file is part of LanternServer, licensed under the MIT License (MIT). * * Copyright (c) LanternPowered <https://www.lanternpowered.org> * Copyright (c) SpongePowered <https://www.spongepowered.org> * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.lanternpowered.server.console.launch; import static com.google.common.base.Preconditions.checkNotNull; import static jline.TerminalFactory.OFF; import com.google.common.collect.Sets; import jline.TerminalFactory; import jline.console.ConsoleReader; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.util.PropertiesUtil; import org.fusesource.jansi.AnsiConsole; import java.util.Set; import java.util.function.Function; import javax.annotation.Nullable; /** * This is the first class that should executed at the start of the * application (or at least before log4j2). */ public final class ConsoleLaunch { // The fqcn of the stream that we use to redirect stream messages through a logger static final Set<String> REDIRECT_FQCNS = Sets.newHashSet(LoggingPrintStream.class.getName()); static final String REDIRECT_ERR = "STDERR"; static final String REDIRECT_OUT = "STDOUT"; // Whether jline should be enabled private static final boolean ENABLE_JLINE = PropertiesUtil.getProperties().getBooleanProperty("jline.enable", true); private static final boolean FORCE_JLINE = PropertiesUtil.getProperties().getBooleanProperty("jline.force", false); static Function<String, String> formatter = Function.identity(); @Nullable static ConsoleReader reader; // Whether the console is initialized static boolean initialized; public static void addFqcn(String fqcn) { REDIRECT_FQCNS.add(checkNotNull(fqcn, "fqcn")); } /** * Gets the {@link ConsoleReader} instance. * * @return the console reader */ @Nullable public static ConsoleReader getReader() { return reader; } /** * Sets the console message formatter. * * @param format the formatter */ public static void setFormatter(@Nullable Function<String, String> format) { formatter = format != null ? format : Function.identity(); } /** * Initializes the console and log manager. */ static void init(Logger logger) { if (initialized) { return; } initialized = true; if (ENABLE_JLINE) { final boolean hasConsole = System.console() != null; if (hasConsole) { try { // Install jansi AnsiConsole.systemInstall(); reader = new ConsoleReader(); reader.setExpandEvents(false); } catch (Exception e) { logger.warn("Failed to initialize terminal. Falling back to default.", e); } } if (reader == null) { // Eclipse doesn't support colors and characters like \r so enabling jline2 on it will // just cause a lot of issues with empty lines and weird characters. // Enable jline2 only on IntelliJ IDEA to prevent that. // Also see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=76936 // Disable advanced jline features TerminalFactory.configure(OFF); TerminalFactory.reset(); if (hasConsole || FORCE_JLINE || System.getProperty("java.class.path").contains("idea_rt.jar")) { // Disable advanced jline features TerminalFactory.configure(OFF); TerminalFactory.reset(); try { reader = new ConsoleReader(); } catch (Exception e) { logger.warn("Failed to initialize fallback terminal. Falling back to standard output console.", e); } } else { logger.warn("Disabling terminal, you're running in an unsupported environment."); } } } System.setOut(new LoggingPrintStream(LogManager.getLogger(REDIRECT_OUT), Level.INFO)); System.setErr(new LoggingPrintStream(LogManager.getLogger(REDIRECT_ERR), Level.ERROR)); } }