org.browsermob.proxy.jetty.util.ByteBufferOutputStream.java Source code

Java tutorial

Introduction

Here is the source code for org.browsermob.proxy.jetty.util.ByteBufferOutputStream.java

Source

// ========================================================================
// $Id: ByteBufferOutputStream.java,v 1.18 2006/10/08 14:13:19 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.browsermob.proxy.jetty.util;

import org.apache.commons.logging.Log;
import org.browsermob.proxy.jetty.log.LogFactory;

import java.io.IOException;
import java.io.OutputStream;

/* ------------------------------------------------------------ */
/** ByteBuffer OutputStream.
 * This stream is similar to the java.io.ByteArrayOutputStream,
 * except that it maintains a reserve of bytes at the start of the
 * buffer and allows efficient prepending of data.
 *
 * @version $Revision: 1.18 $
 * @author Greg Wilkins (gregw)
 */
public class ByteBufferOutputStream extends OutputStream {
    private static Log log = LogFactory.getLog(ByteBufferOutputStream.class);

    protected byte[] _buf;

    /** The start of data capacity in the buffer 
     */
    private int _start;

    /** The end of data capacity in the buffer
     */
    private int _end;

    /** The last byte of data written to the buffer
     * _start <= _pos <= _end
     */
    private int _pos;

    private int _preReserve;
    private int _postReserve;
    private boolean _resized;
    private boolean _fixed;

    /* ------------------------------------------------------------ */
    /** Constructor. 
     */
    public ByteBufferOutputStream() {
        this(4096, 0, 0);
    }

    /* ------------------------------------------------------------ */
    /** Constructor. 
     * @param capacity Buffer capacity
     */
    public ByteBufferOutputStream(int capacity) {
        this(capacity, 0, 0);
    }

    /* ------------------------------------------------------------ */
    /** Constructor. 
     * @param capacity Buffer capacity.
     * @param preReserve The reserve of byte for prepending
     */
    public ByteBufferOutputStream(int capacity, int preReserve) {
        this(capacity, preReserve, 0);
    }

    /* ------------------------------------------------------------ */
    /** Constructor. 
     * @param bufferSize The size of the buffer == capacity+preReserve+postReserve
     * @param preReserve The reserve of byte for prepending
     * @param postReserve The reserve of byte for appending
     */
    public ByteBufferOutputStream(int bufferSize, int preReserve, int postReserve) {
        _buf = ByteArrayPool.getByteArray(bufferSize);
        _end = _buf.length - postReserve;
        _preReserve = preReserve;
        _start = preReserve;
        _pos = preReserve;
        _postReserve = postReserve;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return  True if the buffer cannot be expanded 
     */
    public boolean isFixed() {
        return _fixed;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @param fixed True if the buffer cannot be expanded 
     */
    public void setFixed(boolean fixed) {
        _fixed = fixed;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The size of valid data in the buffer.
     */
    public int size() {
        return _pos - _start;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The size of the buffer.
     */
    public int bufferSize() {
        return _buf.length;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The capacity of the buffer excluding pre and post reserves. 
     */
    public int capacity() {
        return _end - _start;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The available capacity of the buffer excluding pre and post
     * reserves and data already written.  
     */
    public int spareCapacity() {
        return _end - _pos;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The current pre reserve. 
     */
    public int preReserve() {
        return _start;
    }

    /* ------------------------------------------------------------ */
    /** 
     * @return The current post reserve.
     */
    public int postReserve() {
        return _buf.length - _end;
    }

    /* ------------------------------------------------------------ */
    public void writeTo(OutputStream out) throws IOException {
        out.write(_buf, _start, _pos - _start);
    }

    /* ------------------------------------------------------------ */
    public void write(int b) throws IOException {
        ensureSpareCapacity(1);
        _buf[_pos++] = (byte) b;
    }

    /* ------------------------------------------------------------ */
    public void write(byte[] b) throws IOException {
        ensureSpareCapacity(b.length);
        System.arraycopy(b, 0, _buf, _pos, b.length);
        _pos += b.length;
    }

    /* ------------------------------------------------------------ */
    public void write(byte[] b, int offset, int length) throws IOException {
        ensureSpareCapacity(length);
        System.arraycopy(b, offset, _buf, _pos, length);
        _pos += length;
    }

    /* ------------------------------------------------------------ */
    /** Write byte to start of the buffer.
     * @param b 
     */
    public void prewrite(int b) {
        ensureReserve(1);
        _buf[--_start] = (byte) b;
    }

    /* ------------------------------------------------------------ */
    /** Write byte array to start of the buffer.
     * @param b 
     */
    public void prewrite(byte[] b) {
        ensureReserve(b.length);
        System.arraycopy(b, 0, _buf, _start - b.length, b.length);
        _start -= b.length;
    }

    /* ------------------------------------------------------------ */
    /** Write byte range to start of the buffer.
     * @param b 
     * @param offset 
     * @param length 
     */
    public void prewrite(byte[] b, int offset, int length) {
        ensureReserve(length);
        System.arraycopy(b, offset, _buf, _start - length, length);
        _start -= length;
    }

    /* ------------------------------------------------------------ */
    /** Write bytes into the postreserve.
     * The capacity is not checked.
     * @param b 
     * @param offset 
     * @param length 
     * @exception IOException 
     */
    public void postwrite(byte b) throws IOException {
        _buf[_pos++] = b;
    }

    /* ------------------------------------------------------------ */
    /** Write bytes into the postreserve.
     * The capacity is not checked.
     * @param b 
     * @param offset 
     * @param length 
     * @exception IOException 
     */
    public void postwrite(byte[] b, int offset, int length) throws IOException {
        System.arraycopy(b, offset, _buf, _pos, length);
        _pos += length;
    }

    /* ------------------------------------------------------------ */
    public void flush() throws IOException {
    }

    /* ------------------------------------------------------------ */
    public void resetStream() {
        _pos = _preReserve;
        _start = _preReserve;
    }

    /* ------------------------------------------------------------ */
    public void reset(int reserve) {
        _preReserve = reserve;
        _pos = _preReserve;
        _start = _preReserve;
    }

    /* ------------------------------------------------------------ */
    public void close() throws IOException {
        flush();
    }

    /* ------------------------------------------------------------ */
    public void destroy() {
        if (!_resized)
            ByteArrayPool.returnByteArray(_buf);
        _buf = null;
    }

    /* ------------------------------------------------------------ */
    public void ensureReserve(int n) {
        if (n > _start) {
            if (log.isDebugEnabled())
                log.debug("Reserve: " + n + ">" + _start);
            if ((_pos + n) < _end) {
                if (log.isDebugEnabled())
                    log.debug("Shift reserve: " + _pos + "+" + n + "<" + _end);
                System.arraycopy(_buf, _start, _buf, n, _pos - _start);
                _pos = _pos + n - _start;
                _start = n;
            } else {
                if (log.isDebugEnabled())
                    log.debug("New reserve: " + _pos + "+" + n + ">=" + _end);
                byte[] buf = new byte[_buf.length + n - _start];
                System.arraycopy(_buf, _start, buf, n, _pos - _start);
                _pos = n + _pos - _start;
                _start = n;
                _buf = buf;
                _end = _buf.length - _postReserve;
            }
        }
    }

    /* ------------------------------------------------------------ */
    public void ensureSize(int bufSize) throws IOException {
        ensureSize(bufSize, _preReserve, _postReserve);
    }

    /* ------------------------------------------------------------ */
    public void ensureSize(int bufSize, int pre, int post) throws IOException {
        // Do we have space?
        if (bufSize > _buf.length || pre > _preReserve || post > _postReserve) {
            // Make a bigger buffer if we are allowed.
            if (_fixed)
                throw new IllegalStateException("Fixed");

            byte[] old = _buf;
            _buf = ByteArrayPool.getByteArray(bufSize);

            if (_pos > _start)
                System.arraycopy(old, _start, _buf, pre, _pos - _start);
            if (!_resized)
                ByteArrayPool.returnByteArray(old);

            _end = _buf.length - post;
            _preReserve = pre;
            _start = pre;
            _pos = pre;
            _postReserve = post;
        }
    }

    /* ------------------------------------------------------------ */
    public void ensureSpareCapacity(int n) throws IOException {
        // Do we have space?
        if (n > spareCapacity()) {
            // No, then try flushing what we do have
            if (_pos > _start)
                flush();

            ensureCapacity(n);
        }
    }

    /* ------------------------------------------------------------ */
    public void ensureCapacity(int n) throws IOException {
        // Do we have space?
        if (n > capacity()) {
            // Make a bigger buffer if we are allowed.
            if (_fixed)
                throw new IllegalStateException("Fixed");

            int new_size = ((n + _preReserve + _postReserve + 4095) / 4096) * 4096;

            byte[] old = _buf;
            _buf = new byte[new_size];
            if (_pos > _start)
                System.arraycopy(old, _start, _buf, _start, _pos - _start);
            if (!_resized)
                ByteArrayPool.returnByteArray(old);

            _end = _buf.length - _postReserve;
            _resized = true;
        }
    }
}