001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.access.servlet;
015
016import java.io.ByteArrayOutputStream;
017import java.io.IOException;
018
019import javax.servlet.ServletOutputStream;
020import javax.servlet.ServletResponse;
021import javax.servlet.WriteListener;
022
023public class TeeServletOutputStream extends ServletOutputStream {
024
025    final ServletOutputStream underlyingStream;
026    final ByteArrayOutputStream baosCopy;
027
028    TeeServletOutputStream(ServletResponse httpServletResponse) throws IOException {
029        // System.out.println("TeeServletOutputStream.constructor() called");
030        this.underlyingStream = httpServletResponse.getOutputStream();
031        baosCopy = new ByteArrayOutputStream();
032    }
033
034    byte[] getOutputStreamAsByteArray() {
035        return baosCopy.toByteArray();
036    }
037 
038    @Override
039    public void write(int val) throws IOException {
040        if (underlyingStream != null) {
041            underlyingStream.write(val);
042            baosCopy.write(val);
043        }
044    }
045
046    @Override
047    public void write(byte[] byteArray) throws IOException {
048        if (underlyingStream == null) {
049            return;
050        }
051        // System.out.println("WRITE TeeServletOutputStream.write(byte[]) called");
052        write(byteArray, 0, byteArray.length);
053    }
054
055    @Override
056    public void write(byte byteArray[], int offset, int length) throws IOException {
057        if (underlyingStream == null) {
058            return;
059        }
060        // System.out.println("WRITE TeeServletOutputStream.write(byte[], int, int)
061        // called");
062        // System.out.println(new String(byteArray, offset, length));
063        underlyingStream.write(byteArray, offset, length);
064        baosCopy.write(byteArray, offset, length);
065    }
066
067    @Override
068    public void close() throws IOException {
069        // System.out.println("CLOSE TeeServletOutputStream.close() called");
070
071        // If the servlet accessing the stream is using a writer instead of
072        // an OutputStream, it will probably call os.close() before calling
073        // writer.close. Thus, the underlying output stream will be called
074        // before the data sent to the writer could be flushed.
075    }
076
077    @Override
078    public void flush() throws IOException {
079        if (underlyingStream == null) {
080            return;
081        }
082        // System.out.println("FLUSH TeeServletOutputStream.flush() called");
083        underlyingStream.flush();
084        baosCopy.flush();
085    }
086
087    @Override
088    public boolean isReady() {
089        throw new RuntimeException("Not yet implemented");
090    }
091
092    @Override
093    public void setWriteListener(WriteListener listener) {
094        throw new RuntimeException("Not yet implemented");
095    }
096}