/* * 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 socket.io; import java.io.DataOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /** * This output stream works in conjunction with the WrappedInputStream * to introduce a protocol for sending arbitrary length data in a * uniform way. This output stream allows variable length data to be * inserted into an existing output stream so that it can be read by * an input stream without reading too many bytes (in case of buffering * by the input stream). *
* This output stream is used like any normal output stream. The protocol * is introduced by the WrappedOutputStream and does not need to be known * by the user of this class. However, for those that are interested, the * method is described below. *
* The output stream writes the requested bytes as packets of binary * information. The packet consists of a header and payload. The header * is two bytes of a single unsigned short (written in network order) * that specifies the length of bytes in the payload. A header value of * 0 indicates that the stream is "closed". *
* Note: For this wrapped output stream to be used,
* the application must call close()
* to end the output.
*
* @see WrappedInputStream
*
* @author Andy Clark, IBM
*
* @version $Id$
*/
public class WrappedOutputStream
extends FilterOutputStream {
//
// Constants
//
/** Default buffer size (1024). */
public static final int DEFAULT_BUFFER_SIZE = 1024;
//
// Data
//
/** Buffer. */
protected byte[] fBuffer;
/** Buffer position. */
protected int fPosition;
/**
* Data output stream. This stream is used to output the block sizes
* into the data stream that are read by the WrappedInputStream.
*
* Note: The data output stream is only used for
* writing the byte count for performance reasons. We avoid the
* method indirection for writing the byte data.
*/
protected DataOutputStream fDataOutputStream;
//
// Constructors
//
/** Constructs a wrapper for the given output stream. */
public WrappedOutputStream(OutputStream stream) {
this(stream, DEFAULT_BUFFER_SIZE);
} //
* Note: Single bytes written to the output stream
* will be buffered
*/
public void write(int b) throws IOException {
fBuffer[fPosition++] = (byte)b;
if (fPosition == fBuffer.length) {
fPosition = 0;
fDataOutputStream.writeInt(fBuffer.length);
super.out.write(fBuffer, 0, fBuffer.length);
}
} // write(int)
/** Writes an array of bytes to the output. */
public void write(byte[] b, int offset, int length)
throws IOException {
// flush existing buffer
if (fPosition > 0) {
flush0();
}
// write header followed by actual bytes
fDataOutputStream.writeInt(length);
super.out.write(b, offset, length);
} // write(byte[])
/**
* Flushes the output buffer, writing all bytes currently in
* the buffer to the output.
*/
public void flush() throws IOException {
flush0();
super.out.flush();
} // flush()
/**
* Closes the output stream. This method must be
* called when done writing all data to the output stream.
*
* Note: This method does not close the
* actual output stream, only makes the input stream see the stream
* closed. Do not write bytes after closing the output stream.
*/
public void close() throws IOException {
flush0();
fDataOutputStream.writeInt(0);
super.out.flush();
} // close()
//
// Protected methods
//
/**
* Flushes the output buffer, writing all bytes currently in
* the buffer to the output. This method does not call the
* flush() method of the output stream; it merely writes the
* remaining bytes in the buffer.
*/
public void flush0() throws IOException {
int length = fPosition;
fPosition = 0;
if (length > 0) {
fDataOutputStream.writeInt(length);
super.out.write(fBuffer, 0, length);
}
} // flush0()
} // class WrappedOutputStream