Package org.springframework.roo.shell.jline

Source Code of org.springframework.roo.shell.jline.JLineLogHandler

package org.springframework.roo.shell.jline;

import static org.apache.commons.io.IOUtils.LINE_SEPARATOR;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jline.ANSIBuffer;
import jline.ConsoleReader;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.lang3.Validate;
import org.springframework.roo.shell.ShellPromptAccessor;
import org.springframework.roo.support.util.AnsiEscapeCode;

/**
* JDK logging {@link Handler} that emits log messages to a JLine
* {@link ConsoleReader}.
*
* @author Ben Alex
* @since 1.0
*/
public class JLineLogHandler extends Handler {

    private static final boolean BRIGHT_COLORS = Boolean
            .getBoolean("roo.bright");
    private static boolean includeThreadName = false;
    private static String lastMessage;
    private static ThreadLocal<Boolean> redrawProhibit = new ThreadLocal<Boolean>();
    private static boolean suppressDuplicateMessages = true;

    public static void cancelRedrawProhibition() {
        redrawProhibit.remove();
    }

    /**
     * Makes text brighter if requested through system property 'roo.bright' and
     * works around issue on Windows in using reverse() in combination with the
     * Jansi lib, which leaves its 'negative' flag set unless reset explicitly.
     *
     * @return new patched ANSIBuffer
     */
    static ANSIBuffer getANSIBuffer() {
        final char esc = (char) 27;
        return new ANSIBuffer() {
            @Override
            public ANSIBuffer attrib(final String str, final int code) {
                if (BRIGHT_COLORS && 30 <= code && code <= 37) {
                    // This is a color code: add a 'bright' code
                    return append(esc + "[" + code + ";1m").append(str).append(
                            ANSICodes.attrib(0));
                }
                return super.attrib(str, code);
            };

            @Override
            public ANSIBuffer reverse(final String str) {
                if (SystemUtils.IS_OS_WINDOWS) {
                    return super.reverse(str).append(ANSICodes.attrib(esc));
                }
                return super.reverse(str);
            }
        };
    }

    public static boolean isSuppressDuplicateMessages() {
        return suppressDuplicateMessages;
    }

    public static void prohibitRedraw() {
        redrawProhibit.set(true);
    }

    public static void resetMessageTracking() {
        lastMessage = null; // see ROO-251
    }

    public static void setIncludeThreadName(final boolean include) {
        includeThreadName = include;
    }

    public static void setSuppressDuplicateMessages(
            final boolean suppressDuplicateMessages) {
        JLineLogHandler.suppressDuplicateMessages = suppressDuplicateMessages;
    }

    private boolean ansiSupported;
    private ConsoleReader reader;
    private ShellPromptAccessor shellPromptAccessor;
    private String userInterfaceThreadName;

    public JLineLogHandler(final ConsoleReader reader,
            final ShellPromptAccessor shellPromptAccessor) {
        Validate.notNull(reader, "Console reader required");
        Validate.notNull(shellPromptAccessor, "Shell prompt accessor required");
        this.reader = reader;
        this.shellPromptAccessor = shellPromptAccessor;
        userInterfaceThreadName = Thread.currentThread().getName();
        ansiSupported = reader.getTerminal().isANSISupported()
                && AnsiEscapeCode.isAnsiEnabled();

        setFormatter(new Formatter() {
            @Override
            public String format(final LogRecord record) {
                final StringBuilder sb = new StringBuilder();
                String message = record.getMessage();
                if (message != null) {
                    final Object[] parameters = record.getParameters();
                    if (!ArrayUtils.isEmpty(parameters)) {
                        final Pattern pattern = Pattern.compile("\\{.*?\\}");
                        final Matcher matcher = pattern.matcher(message);
                        int i = 0;
                        while (matcher.find()) {
                            message = StringUtils.replace(message,
                                    matcher.group(0), parameters[i].toString());
                            i++;
                        }
                    }
                    sb.append(message).append(LINE_SEPARATOR);
                }
                if (record.getThrown() != null) {
                    PrintWriter pw = null;
                    try {
                        final StringWriter sw = new StringWriter();
                        pw = new PrintWriter(sw);
                        record.getThrown().printStackTrace(pw);
                        sb.append(sw.toString());
                    }
                    catch (final Exception ex) {
                    }
                    finally {
                        IOUtils.closeQuietly(pw);
                    }
                }
                return sb.toString();
            }
        });
    }

    @Override
    public void close() throws SecurityException {
    }

    @Override
    public void flush() {
    }

    @Override
    public void publish(final LogRecord record) {
        try {
            // Avoid repeating the same message that displayed immediately
            // before the current message (ROO-30, ROO-1873)
            final String toDisplay = toDisplay(record);
            if (toDisplay.equals(lastMessage) && suppressDuplicateMessages) {
                return;
            }
            lastMessage = toDisplay;

            final StringBuffer buffer = reader.getCursorBuffer().getBuffer();
            final int cursor = reader.getCursorBuffer().cursor;
            if (reader.getCursorBuffer().length() > 0) {
                // The user has semi-typed something, so put a new line in so
                // the debug message is separated
                reader.printNewline();

                // We need to cancel whatever they typed (it's reset later on),
                // so the line appears empty
                reader.getCursorBuffer().setBuffer(new StringBuffer());
                reader.getCursorBuffer().cursor = 0;
            }

            // This ensures nothing is ever displayed when redrawing the line
            reader.setDefaultPrompt("");
            reader.redrawLine();

            // Now restore the line formatting settings back to their original
            reader.setDefaultPrompt(shellPromptAccessor.getShellPrompt());

            reader.getCursorBuffer().setBuffer(buffer);
            reader.getCursorBuffer().cursor = cursor;

            reader.printString(toDisplay);

            final Boolean prohibitingRedraw = redrawProhibit.get();
            if (prohibitingRedraw == null) {
                reader.redrawLine();
            }

            reader.flushConsole();
        }
        catch (final Exception e) {
            reportError("Could not publish log message", e,
                    Level.SEVERE.intValue());
        }
    }

    private String toDisplay(final LogRecord event) {
        final StringBuilder sb = new StringBuilder();

        String threadName;
        String eventString;
        if (includeThreadName
                && !userInterfaceThreadName.equals(Thread.currentThread()
                        .getName())
                && !"".equals(Thread.currentThread().getName())) {
            threadName = "[" + Thread.currentThread().getName() + "]";

            // Build an event string that will indent nicely given the left hand
            // side now contains a thread name
            final StringBuilder lineSeparatorAndIndentingString = new StringBuilder();
            for (int i = 0; i <= threadName.length(); i++) {
                lineSeparatorAndIndentingString.append(" ");
            }

            eventString = " "
                    + getFormatter().format(event).replace(
                            LINE_SEPARATOR,
                            LINE_SEPARATOR
                                    + lineSeparatorAndIndentingString
                                            .toString());
            if (eventString
                    .endsWith(lineSeparatorAndIndentingString.toString())) {
                eventString = eventString.substring(0, eventString.length()
                        - lineSeparatorAndIndentingString.length());
            }
        }
        else {
            threadName = "";
            eventString = getFormatter().format(event);
        }

        if (ansiSupported) {
            if (event.getLevel().intValue() >= Level.SEVERE.intValue()) {
                sb.append(getANSIBuffer().reverse(threadName).red(eventString));
            }
            else if (event.getLevel().intValue() >= Level.WARNING.intValue()) {
                sb.append(getANSIBuffer().reverse(threadName).magenta(
                        eventString));
            }
            else if (event.getLevel().intValue() >= Level.INFO.intValue()) {
                sb.append(getANSIBuffer().reverse(threadName)
                        .green(eventString));
            }
            else {
                sb.append(getANSIBuffer().reverse(threadName).append(
                        eventString));
            }
        }
        else {
            sb.append(threadName).append(eventString);
        }

        return sb.toString();
    }
}
TOP

Related Classes of org.springframework.roo.shell.jline.JLineLogHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.