001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018 019 package org.apache.commons.exec; 020 021 import java.io.ByteArrayOutputStream; 022 import java.io.IOException; 023 import java.io.OutputStream; 024 025 /** 026 * Base class to connect a logging system to the output and/or 027 * error stream of then external process. The implementation 028 * parses the incoming data to construct a line and passes 029 * the complete line to an user-defined implementation. 030 */ 031 public abstract class LogOutputStream 032 extends OutputStream { 033 034 /** Initial buffer size. */ 035 private static final int INTIAL_SIZE = 132; 036 037 /** Carriage return */ 038 private static final int CR = 0x0d; 039 040 /** Linefeed */ 041 private static final int LF = 0x0a; 042 043 /** the internal buffer */ 044 private final ByteArrayOutputStream buffer = new ByteArrayOutputStream( 045 INTIAL_SIZE); 046 047 private boolean skip = false; 048 049 private final int level; 050 051 /** 052 * Creates a new instance of this class. 053 * Uses the default level of 999. 054 */ 055 public LogOutputStream() { 056 this(999); 057 } 058 059 /** 060 * Creates a new instance of this class. 061 * 062 * @param level loglevel used to log data written to this stream. 063 */ 064 public LogOutputStream(final int level) { 065 this.level = level; 066 } 067 068 /** 069 * Write the data to the buffer and flush the buffer, if a line separator is 070 * detected. 071 * 072 * @param cc data to log (byte). 073 * @see java.io.OutputStream#write(int) 074 */ 075 public void write(final int cc) throws IOException { 076 final byte c = (byte) cc; 077 if ((c == '\n') || (c == '\r')) { 078 if (!skip) { 079 processBuffer(); 080 } 081 } else { 082 buffer.write(cc); 083 } 084 skip = (c == '\r'); 085 } 086 087 /** 088 * Flush this log stream. 089 * 090 * @see java.io.OutputStream#flush() 091 */ 092 public void flush() { 093 if (buffer.size() > 0) { 094 processBuffer(); 095 } 096 } 097 098 /** 099 * Writes all remaining data from the buffer. 100 * 101 * @see java.io.OutputStream#close() 102 */ 103 public void close() throws IOException { 104 if (buffer.size() > 0) { 105 processBuffer(); 106 } 107 super.close(); 108 } 109 110 /** 111 * @return the trace level of the log system 112 */ 113 public int getMessageLevel() { 114 return level; 115 } 116 117 /** 118 * Write a block of characters to the output stream 119 * 120 * @param b the array containing the data 121 * @param off the offset into the array where data starts 122 * @param len the length of block 123 * @throws java.io.IOException if the data cannot be written into the stream. 124 * @see java.io.OutputStream#write(byte[], int, int) 125 */ 126 public void write(final byte[] b, final int off, final int len) 127 throws IOException { 128 // find the line breaks and pass other chars through in blocks 129 int offset = off; 130 int blockStartOffset = offset; 131 int remaining = len; 132 while (remaining > 0) { 133 while (remaining > 0 && b[offset] != LF && b[offset] != CR) { 134 offset++; 135 remaining--; 136 } 137 // either end of buffer or a line separator char 138 int blockLength = offset - blockStartOffset; 139 if (blockLength > 0) { 140 buffer.write(b, blockStartOffset, blockLength); 141 } 142 while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) { 143 write(b[offset]); 144 offset++; 145 remaining--; 146 } 147 blockStartOffset = offset; 148 } 149 } 150 151 /** 152 * Converts the buffer to a string and sends it to <code>processLine</code>. 153 */ 154 protected void processBuffer() { 155 processLine(buffer.toString()); 156 buffer.reset(); 157 } 158 159 /** 160 * Logs a line to the log system of the user. 161 * 162 * @param line 163 * the line to log. 164 */ 165 protected void processLine(final String line) { 166 processLine(line, level); 167 } 168 169 /** 170 * Logs a line to the log system of the user. 171 * 172 * @param line the line to log. 173 * @param level the log level to use 174 */ 175 protected abstract void processLine(final String line, final int level); 176 }