| // ======================================================================== |
| // $Id: BufferedOutputStream.java,v 1.8 2006/06/29 12:41:11 gregwilkins Exp $ |
| // Copyright 2001-2004 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // Licensed 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 org.openqa.jetty.http; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import org.openqa.jetty.util.ByteArrayISO8859Writer; |
| import org.openqa.jetty.util.ByteBufferOutputStream; |
| import org.openqa.jetty.util.OutputObserver; |
| |
| /* ------------------------------------------------------------ */ |
| /** Buffered Output Stream. |
| * Uses ByteBufferOutputStream to allow pre and post writes. |
| * @version $Revision: 1.8 $ |
| * @author Greg Wilkins (gregw) |
| */ |
| public class BufferedOutputStream |
| extends ByteBufferOutputStream |
| implements HttpMessage.HeaderWriter |
| { |
| protected OutputStream _out; |
| protected ByteArrayISO8859Writer _httpMessageWriter; |
| private OutputObserver _commitObserver; |
| private boolean _commited ; |
| private int _preReserve; |
| private boolean _bypassBuffer ; |
| |
| /* ------------------------------------------------------------ */ |
| /** Constructor. |
| * @param out the OutputStream to buffer to. |
| * @param capacity Buffer capacity. |
| * @param headerReserve The reserve of bytes for prepending to be used |
| * for the first buffer after reset |
| * @param preReserve The reserve of bytes for prepending |
| * @param postReserve The reserve of bytes for appending |
| */ |
| public BufferedOutputStream(OutputStream out, |
| int capacity, |
| int headerReserve, |
| int preReserve, |
| int postReserve) |
| { |
| super(capacity,headerReserve,postReserve); |
| _out=out; |
| _preReserve=preReserve; |
| _httpMessageWriter = new ByteArrayISO8859Writer(headerReserve); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public OutputStream getOutputStream() |
| { |
| return _out; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return OutputObserver to receives commit events from this stream. |
| */ |
| public OutputObserver getCommitObserver() |
| { |
| return _commitObserver; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param commitObserver OutputObserver to receives commit events from this stream. |
| */ |
| public void setCommitObserver(OutputObserver commitObserver) |
| { |
| _commitObserver = commitObserver; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public boolean isCommitted() |
| { |
| return _commited; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return If true, the buffer is bypassed for large writes |
| * to a committed stream. |
| */ |
| public boolean getBypassBuffer() |
| { |
| return _bypassBuffer; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param bypassBuffer If true, the buffer is bypassed for large writes |
| * to a committed stream. |
| */ |
| public void setBypassBuffer(boolean bypassBuffer) |
| { |
| _bypassBuffer = bypassBuffer; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void writeHeader(HttpMessage httpMessage) |
| throws IOException |
| { |
| httpMessage.writeHeader(_httpMessageWriter); |
| if (_httpMessageWriter.size()>capacity()) |
| throw new IllegalStateException("Header too large"); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void write(byte[] b) |
| throws IOException |
| { |
| write(b,0,b.length); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void write(byte[] b, int offset, int length) |
| throws IOException |
| { |
| int o=offset; |
| int l=length; |
| while (l>0) |
| { |
| int c=capacity(); |
| |
| if (_bypassBuffer && isCommitted() && size()==0 && l>c) |
| { |
| // Bypass buffer |
| bypassWrite(b,o,l); |
| break; |
| } |
| |
| if (l<c || !isFixed()) |
| { |
| // Write all |
| super.write(b,o,l); |
| break; |
| } |
| else |
| { |
| // Write a block |
| super.write(b,o,c); |
| flush(); |
| l-=c; |
| o+=c; |
| } |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected void bypassWrite(byte[] b, int offset, int length) |
| throws IOException |
| { |
| try |
| { |
| _out.write(b,offset,length); |
| _out.flush(); |
| } |
| catch (IOException e) |
| { |
| throw new EOFException(e); |
| } |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * This implementation calls the commitObserver on the first flush since |
| * construction or reset. |
| */ |
| public void flush() |
| throws IOException |
| { |
| try |
| { |
| if (!_commited) |
| { |
| _commited=true; |
| if (_commitObserver!=null) |
| _commitObserver.outputNotify(this,OutputObserver.__COMMITING,null); |
| } |
| |
| wrapBuffer(); |
| |
| // Add headers |
| if (_httpMessageWriter.size()>0) |
| { |
| prewrite(_httpMessageWriter.getBuf(),0,_httpMessageWriter.size()); |
| _httpMessageWriter.resetWriter(); |
| } |
| |
| if (size()>0) |
| writeTo(_out); |
| } |
| catch (IOException e) |
| { |
| throw new EOFException(e); |
| } |
| finally |
| { |
| reset(_preReserve); |
| } |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** Wrap Buffer. |
| * Called by flush() to allow the data in the buffer to be pre and post |
| * written for any protocol wrapping. The default implementation does |
| * nothing. |
| * @exception IOException |
| */ |
| protected void wrapBuffer() |
| throws IOException |
| { |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void close() |
| throws IOException |
| { |
| flush(); |
| _out.close(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void resetStream() |
| { |
| super.reset(_httpMessageWriter.capacity()); |
| _commited=false; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public void destroy() |
| { |
| super.destroy(); |
| if (_httpMessageWriter!=null) |
| _httpMessageWriter.destroy(); |
| _httpMessageWriter=null; |
| _out=null; |
| } |
| |
| } |