com.synopsys.integration.blackduck.service.model.ScannerSplitStream.java Source code

Java tutorial

Introduction

Here is the source code for com.synopsys.integration.blackduck.service.model.ScannerSplitStream.java

Source

/**
 * blackduck-common
 *
 * Copyright (c) 2019 Synopsys, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 com.synopsys.integration.blackduck.service.model;

import java.io.EOFException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import org.apache.commons.lang3.StringUtils;

import com.synopsys.integration.log.IntLogger;

public class ScannerSplitStream extends OutputStream {
    // https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
    private static final int EOF = -1; // End of file

    private static final int ETX = 3; // End of text, should have no more data

    private static final int EOT = 4; // End of transmission, no more data

    private static final int LF = 10; // Line feed, new line

    private static final int CR = 13; // Carriage return

    private static final String EXCEPTION = "Exception:";

    private static final String FINISHED = "Finished in";

    private static final String ERROR = "ERROR:";

    private static final String WARN = "WARN:";

    private static final String INFO = "INFO:";

    private static final String DEBUG = "DEBUG:";

    private static final String TRACE = "TRACE:";

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    private final OutputStream outputFileStream;

    private final IntLogger logger;

    private String output = "";

    private String lineBuffer = "";

    private String currentLine = "";

    private int previousCodePoint = -1;

    public ScannerSplitStream(final IntLogger logger, final OutputStream outputFileStream) {
        this.outputFileStream = outputFileStream;
        this.logger = logger;
    }

    public String getOutput() {
        return output;
    }

    public Boolean hasOutput() {
        return StringUtils.isNotBlank(output);
    }

    @Override
    public void write(final int codePoint) throws IOException {
        outputFileStream.write(codePoint);

        if (EOF == codePoint) {
            throw new EOFException();
        }

        boolean atLineEnd = false;
        if (ETX == codePoint || EOT == codePoint) {
            atLineEnd = true;
        } else if (LF == codePoint && CR != previousCodePoint) {
            atLineEnd = true;
        } else if (LF == codePoint && CR == previousCodePoint) {
            atLineEnd = true;
            // also need to remove the previously consumed CR
            currentLine = currentLine.substring(0, currentLine.length() - 1);
        } else if (LF != codePoint && CR == previousCodePoint) {
            processLine(currentLine);
            currentLine = "";
        }
        previousCodePoint = codePoint;

        if (atLineEnd) {
            processLine(currentLine);
            currentLine = "";
        } else {
            final String stringAscii = new String(Character.toChars(codePoint));
            currentLine += stringAscii;
        }
    }

    private Boolean isLoggableLine(final String line) {
        final String trimmedLine = line.trim();
        if (trimmedLine.startsWith(ERROR)) {
            return true;
        }
        if (trimmedLine.startsWith(WARN)) {
            return true;
        }
        if (trimmedLine.startsWith(INFO)) {
            return true;
        }
        if (trimmedLine.startsWith(DEBUG)) {
            return true;
        }
        if (trimmedLine.startsWith(TRACE)) {
            return true;
        }
        if (StringUtils.containsIgnoreCase(trimmedLine, EXCEPTION)) {
            return true;
        }
        if (StringUtils.containsIgnoreCase(trimmedLine, FINISHED)) {
            return true;
        }
        return false;
    }

    private void processLine(final String line) throws UnsupportedEncodingException {
        if (lineBuffer.length() == 0) {
            // First log line found, put it in the buffer
            lineBuffer = line;
        } else if (isLoggableLine(line)) {
            // next real log message came in, print the log in the buffer
            // print stored lines
            writeToConsole(lineBuffer);

            // replace with the current line
            lineBuffer = line;
        } else {
            // We assume that each new log starts with the log level, if this
            // line does not contain a log level it
            // must only be a piece of a log
            // needs to be added into the buffer
            final StringBuilder builder = new StringBuilder();
            builder.append(lineBuffer);

            builder.append(LINE_SEPARATOR);
            builder.append(line);
            lineBuffer = builder.toString();
        }
    }

    @Override
    public void write(final byte[] byteArray) throws IOException {
        outputFileStream.write(byteArray);

        final String currentLine = new String(byteArray, "UTF-8");
        if (currentLine.contains(LINE_SEPARATOR)) {
            final String[] splitLines = currentLine.split(LINE_SEPARATOR);

            for (final String line : splitLines) {
                processLine(line);
            }
        } else {
            processLine(currentLine);
        }
    }

    @Override
    public void write(final byte[] byteArray, final int offset, final int length) throws IOException {
        outputFileStream.write(byteArray, offset, length);

        final String currentLine = new String(byteArray, offset, length, "UTF-8");
        if (currentLine.contains(LINE_SEPARATOR)) {
            final String[] splitLines = currentLine.split(LINE_SEPARATOR);

            for (final String line : splitLines) {
                processLine(line);
            }
        } else {
            processLine(currentLine);
        }
    }

    @Override
    public void flush() throws IOException {
        outputFileStream.flush();

        // Print whatever is left in the buffer
        writeToConsole(lineBuffer);
        lineBuffer = "";
        // Print whatever is left in the buffer
        if (StringUtils.isNotBlank(currentLine)) {
            writeToConsole(currentLine);
            currentLine = "";
        }
    }

    @Override
    public void close() throws IOException {
        outputFileStream.close();

        // Do not close the listener, will not be able to log to the UI anymore
        // if you do
    }

    private void writeToConsole(final String line) {
        final String trimmedLine = line.trim();
        if (trimmedLine.startsWith(DEBUG) || trimmedLine.startsWith(TRACE)) {
            // We dont want to print Debug or Trace logs to the logger
            return;
        }
        final StringBuilder outputBuilder = new StringBuilder();
        outputBuilder.append(output);
        if (trimmedLine.startsWith(ERROR)) {
            outputBuilder.append(trimmedLine);
            outputBuilder.append(LINE_SEPARATOR);
            logger.error(trimmedLine);
        } else if (trimmedLine.startsWith(WARN)) {
            outputBuilder.append(trimmedLine);
            outputBuilder.append(LINE_SEPARATOR);
            logger.warn(trimmedLine);
        } else if (trimmedLine.startsWith(INFO)) {
            outputBuilder.append(trimmedLine);
            outputBuilder.append(LINE_SEPARATOR);
            logger.info(trimmedLine);
        } else if (StringUtils.containsIgnoreCase(trimmedLine, EXCEPTION)) {
            // looking for 'Exception in thread' type messages
            outputBuilder.append(trimmedLine);
            outputBuilder.append(LINE_SEPARATOR);
            logger.error(trimmedLine);
        } else if (StringUtils.containsIgnoreCase(trimmedLine, FINISHED)) {
            outputBuilder.append(trimmedLine);
            outputBuilder.append(LINE_SEPARATOR);
            logger.info(trimmedLine);
        }

        output = outputBuilder.toString();
    }

}