001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.util;
018:
019: import java.io.FilterOutputStream;
020: import java.io.IOException;
021: import java.io.OutputStream;
022:
023: /**
024: * This class is like the {@link java.io.BufferedOutputStream} but it
025: * extends it with a logic to count the number of bytes written to
026: * the output stream.
027: *
028: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
029: * @version CVS $Id: BufferedOutputStream.java 433543 2006-08-22 06:22:54Z crossley $
030: * @since 2.1
031: */
032: public final class BufferedOutputStream extends FilterOutputStream {
033:
034: protected byte buf[];
035:
036: protected int count;
037:
038: /**
039: * Creates a new buffered output stream to write data to the
040: * specified underlying output stream with a default 8192-byte
041: * buffer size.
042: *
043: * @param out the underlying output stream.
044: */
045: public BufferedOutputStream(OutputStream out) {
046: this (out, 8192);
047: }
048:
049: /**
050: * Creates a new buffered output stream to write data to the
051: * specified underlying output stream with the specified buffer
052: * size.
053: *
054: * @param out the underlying output stream.
055: * @param size the buffer size.
056: * @exception IllegalArgumentException if size <= 0.
057: */
058: public BufferedOutputStream(OutputStream out, int size) {
059: super (out);
060: if (size <= 0) {
061: throw new IllegalArgumentException("Buffer size <= 0");
062: }
063: this .buf = new byte[size];
064: }
065:
066: /**
067: * Writes the specified byte to this buffered output stream.
068: *
069: * @param b the byte to be written.
070: * @exception IOException if an I/O error occurs.
071: */
072: public void write(int b) throws IOException {
073: if (this .count >= this .buf.length) {
074: this .incBuffer();
075: }
076: this .buf[count++] = (byte) b;
077: }
078:
079: /**
080: * Writes <code>len</code> bytes from the specified byte array
081: * starting at offset <code>off</code> to this buffered output stream.
082: *
083: * <p> Ordinarily this method stores bytes from the given array into this
084: * stream's buffer, flushing the buffer to the underlying output stream as
085: * needed. If the requested length is at least as large as this stream's
086: * buffer, however, then this method will flush the buffer and write the
087: * bytes directly to the underlying output stream. Thus redundant
088: * <code>BufferedOutputStream</code>s will not copy data unnecessarily.
089: *
090: * @param b the data.
091: * @param off the start offset in the data.
092: * @param len the number of bytes to write.
093: * @exception IOException if an I/O error occurs.
094: */
095: public void write(byte b[], int off, int len) throws IOException {
096: while (len > buf.length - count) {
097: this .incBuffer();
098: }
099: System.arraycopy(b, off, buf, count, len);
100: count += len;
101: }
102:
103: /**
104: * Flushes this buffered output stream.
105: * We don't flush here, flushing is done during closing.
106: *
107: * @exception IOException if an I/O error occurs.
108: */
109: public void flush() throws IOException {
110: // nothing
111: }
112:
113: /**
114: * Closes this buffered output stream.
115: * Flush before closing.
116: *
117: * @exception IOException if an I/O error occurs.
118: */
119: public void close() throws IOException {
120: realFlush();
121: super .close();
122: }
123:
124: /**
125: * Flushes this buffered output stream.
126: */
127: public void realFlush() throws IOException {
128: this .writeBuffer();
129: this .out.flush();
130: }
131:
132: /**
133: * Write the buffer
134: */
135: private void writeBuffer() throws IOException {
136: if (this .count > 0) {
137: this .out.write(this .buf, 0, this .count);
138: this .clearBuffer();
139: }
140: }
141:
142: /**
143: * Increment the buffer
144: */
145: private void incBuffer() {
146: // currently we double the buffer size
147: // this is not so fast but is a very simple logic
148: byte[] newBuf = new byte[this .buf.length * 2];
149: System.arraycopy(this .buf, 0, newBuf, 0, this .buf.length);
150: this .buf = newBuf;
151: }
152:
153: /**
154: * Clear/reset the buffer
155: */
156: public void clearBuffer() {
157: this .count = 0;
158: }
159:
160: /**
161: * Return the size of the current buffer
162: */
163: public int getCount() {
164: return this.count;
165: }
166: }
|