On 29.05.2008 00:06, Joerg Heinicke wrote:
Only issue I want to solve before the release is the BufferedOutputStream issue. I planned to do it this weekend.
Done. Please review the file attached. It's still completely untested. At the moment I need some sleep ;) I will write junit tests for it this week and eventually commit it.
Joerg
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.cocoon.util; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /** * This class is similar to the [EMAIL PROTECTED] java.io.BufferedOutputStream}. In * addition it provides an increasing buffer, the possibility to reset the * buffer and it counts the number of bytes written to the output stream. * * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a> * @version CVS $Id: BufferedOutputStream.java 433543 2006-08-22 06:22:54Z crossley $ * @since 2.1 */ public class BufferedOutputStream extends FilterOutputStream { private byte buffer[]; private int count; private int totalCount; private final int flushBufferSize; /** * Creates a new buffered output stream to write data to the * specified underlying output stream with a default 8192-byte * buffer size. * * @param out the underlying output stream. */ public BufferedOutputStream(final OutputStream out) { this(out, 8192, 32768); } /** * Creates a new buffered output stream to write data to the specified * underlying output stream with the specified buffer sizes. * * @param out the underlying output stream. * @param initialBufferSize the initial buffer size. Must be greater than 0. * Will be limited to the flush buffer size. * @param flushBufferSize the buffer size when the stream is flushed. Must * be greater than 0 or -1 meaning the stream never * flushes itself. */ public BufferedOutputStream(final OutputStream out, final int initialBufferSize, final int flushBufferSize) { super(out); if (initialBufferSize <= 0) { throw new IllegalArgumentException("Initial buffer size <= 0"); } if (flushBufferSize <= 0 && flushBufferSize != -1) { throw new IllegalArgumentException("Flush buffer size <= 0 && != -1"); } this.buffer = new byte[initialBufferSize > flushBufferSize ? flushBufferSize : initialBufferSize]; this.flushBufferSize = flushBufferSize; } /** * Writes the specified byte to this buffered output stream. * * @param b the byte to be written. * @exception IOException if an I/O error occurs. */ public void write(int b) throws IOException { if (this.count == this.buffer.length) { // No need to check return value, can NEVER be 0. this.increaseBuffer(1); } this.buffer[this.count++] = (byte)b; this.totalCount++; if (this.count == this.flushBufferSize) { flush(); } } /** * Writes <code>len</code> bytes from the specified byte array * starting at offset <code>off</code> to this buffered output stream. * * <p> Ordinarily this method stores bytes from the given array into this * stream's buffer, flushing the buffer to the underlying output stream as * needed. If the requested length is at least as large as this stream's * buffer, however, then this method will flush the buffer and write the * bytes directly to the underlying output stream. Thus redundant * <code>BufferedOutputStream</code>s will not copy data unnecessarily. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. * @exception IOException if an I/O error occurs. */ public void write(final byte[] b, final int off, final int len) throws IOException { if (len > this.buffer.length - this.count) { int actualIncrease = this.increaseBuffer(len); if (actualIncrease < len) { // Needs to be written in chunks by recursive calls to this method. write(b, off, actualIncrease); write(b, off + actualIncrease, len - actualIncrease); return; } } System.arraycopy(b, off, this.buffer, this.count, len); this.count += len; this.totalCount += len; if (this.count == this.flushBufferSize) { flush(); } } /** * Flushes this buffered output stream. * * @exception IOException if an I/O error occurs. */ public void flush() throws IOException { writeBuffer(); this.out.flush(); } /** * Closes this buffered output stream. * Flush before closing. * * @exception IOException if an I/O error occurs. */ public void close() throws IOException { flush(); super.close(); } /** * Write the buffer */ private void writeBuffer() throws IOException { if (this.count > 0) { this.out.write(this.buffer, 0, this.count); this.clearBuffer(); } } /** * Increase the buffer by at least as many bytes as specified via the * parameter, but not exceeding the flushBufferSize. The actual increase is * returned. * * @return increase in buffer size. */ private int increaseBuffer(final int increase) { int oldLength = this.buffer.length; if (oldLength == this.flushBufferSize) { // fast way out return 0; } int newLength = oldLength; int actualIncrease; do { newLength = newLength * 2; if (this.flushBufferSize > 0 && newLength >= this.flushBufferSize) { newLength = this.flushBufferSize; actualIncrease = newLength - oldLength; break; } actualIncrease = newLength - oldLength; } while (actualIncrease < increase); // Because of the "fast way out" above at this point there should always be an increase. byte[] newBuffer = new byte[newLength]; if (this.count > 0) { System.arraycopy(this.buffer, 0, newBuffer, 0, this.count); } this.buffer = newBuffer; return actualIncrease; } /** * Clear/reset the buffer * @deprecated Public access is deprecated. Use [EMAIL PROTECTED] #reset()} instead. */ public void clearBuffer() { this.count = 0; } /** * Reset the BufferedOutputStream to the last [EMAIL PROTECTED] #flush()}. */ public void reset() { this.clearBuffer(); } /** * Return the size of the current buffer */ public int getCount() { return this.totalCount; } }