You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

DemuxOutputStream.java 7.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2001-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant;
  55. import java.io.OutputStream;
  56. import java.io.ByteArrayOutputStream;
  57. import java.io.IOException;
  58. import java.util.Hashtable;
  59. /**
  60. * Logs content written by a thread and forwards the buffers onto the
  61. * project object which will forward the content to the appropriate
  62. * task.
  63. *
  64. * @since 1.4
  65. * @author Conor MacNeill
  66. */
  67. public class DemuxOutputStream extends OutputStream {
  68. /**
  69. * A data class to store information about a buffer. Such information
  70. * is stored on a per-thread basis.
  71. */
  72. private static class BufferInfo {
  73. /**
  74. * The per-thread output stream.
  75. */
  76. private ByteArrayOutputStream buffer;
  77. /**
  78. * Whether or not the next line-terminator should be skipped in terms
  79. * of processing the buffer. Used to avoid \r\n invoking
  80. * processBuffer twice.
  81. */
  82. private boolean skip = false;
  83. }
  84. /** Maximum buffer size. */
  85. private final static int MAX_SIZE = 1024;
  86. /** Mapping from thread to buffer (Thread to BufferInfo). */
  87. private Hashtable buffers = new Hashtable();
  88. /**
  89. * The project to send output to.
  90. */
  91. private Project project;
  92. /**
  93. * Whether or not this stream represents an error stream.
  94. */
  95. private boolean isErrorStream;
  96. /**
  97. * Creates a new instance of this class.
  98. *
  99. * @param project The project instance for which output is being
  100. * demultiplexed. Must not be <code>null</code>.
  101. * @param isErrorStream <code>true</code> if this is the error string,
  102. * otherwise a normal output stream. This is
  103. * passed to the project so it knows
  104. * which stream it is receiving.
  105. */
  106. public DemuxOutputStream(Project project, boolean isErrorStream) {
  107. this.project = project;
  108. this.isErrorStream = isErrorStream;
  109. }
  110. /**
  111. * Returns the buffer associated with the current thread.
  112. *
  113. * @return a BufferInfo for the current thread to write data to
  114. */
  115. private BufferInfo getBufferInfo() {
  116. Thread current = Thread.currentThread();
  117. BufferInfo bufferInfo = (BufferInfo)buffers.get(current);
  118. if (bufferInfo == null) {
  119. bufferInfo = new BufferInfo();
  120. bufferInfo.buffer = new ByteArrayOutputStream();
  121. bufferInfo.skip = false;
  122. buffers.put(current, bufferInfo);
  123. }
  124. return bufferInfo;
  125. }
  126. /**
  127. * Resets the buffer for the current thread.
  128. */
  129. private void resetBufferInfo() {
  130. Thread current = Thread.currentThread();
  131. BufferInfo bufferInfo = (BufferInfo)buffers.get(current);
  132. try {
  133. bufferInfo.buffer.close();
  134. }
  135. catch (IOException e) {
  136. // Shouldn't happen
  137. }
  138. bufferInfo.buffer = new ByteArrayOutputStream();
  139. bufferInfo.skip = false;
  140. }
  141. /**
  142. * Removes the buffer for the current thread.
  143. */
  144. private void removeBuffer() {
  145. Thread current = Thread.currentThread();
  146. buffers.remove (current);
  147. }
  148. /**
  149. * Writes the data to the buffer and flushes the buffer if a line
  150. * separator is detected or if the buffer has reached its maximum size.
  151. *
  152. * @param cc data to log (byte).
  153. * @exception IOException if the data cannot be written to the stream
  154. */
  155. public void write(int cc) throws IOException {
  156. final byte c = (byte)cc;
  157. BufferInfo bufferInfo = getBufferInfo();
  158. if ((c == '\n') || (c == '\r')) {
  159. if (!bufferInfo.skip) {
  160. processBuffer(bufferInfo.buffer);
  161. }
  162. } else {
  163. bufferInfo.buffer.write(cc);
  164. if (bufferInfo.buffer.size() > MAX_SIZE) {
  165. processBuffer(bufferInfo.buffer);
  166. }
  167. }
  168. bufferInfo.skip = (c == '\r');
  169. }
  170. /**
  171. * Converts the buffer to a string and sends it to the project.
  172. *
  173. * @param buffer the ByteArrayOutputStream used to collect the output
  174. * until a line separator is seen.
  175. *
  176. * @see Project#demuxOutput(String,boolean)
  177. */
  178. protected void processBuffer(ByteArrayOutputStream buffer) {
  179. String output = buffer.toString();
  180. project.demuxOutput(output, isErrorStream);
  181. resetBufferInfo();
  182. }
  183. /**
  184. * Equivalent to flushing the stream.
  185. *
  186. * @exception IOException if there is a problem closing the stream.
  187. *
  188. * @see #flush
  189. */
  190. public void close() throws IOException {
  191. flush();
  192. removeBuffer();
  193. }
  194. /**
  195. * Writes all remaining data in the buffer associated
  196. * with the current thread to the project.
  197. *
  198. * @exception IOException if there is a problem flushing the stream.
  199. */
  200. public void flush() throws IOException {
  201. BufferInfo bufferInfo = getBufferInfo();
  202. if (bufferInfo.buffer.size() > 0) {
  203. processBuffer(bufferInfo.buffer);
  204. }
  205. }
  206. }