/* * This program is free software; you can redistribute it and/or modify it under the terms of * the GNU AFFERO GENERAL PUBLIC LICENSE as published by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU AFFERO GENERAL PUBLIC LICENSE for more details. * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE along with this program; * if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package com.meidusa.amoeba.net.io; import java.io.OutputStream; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; /** * * @author <a href=mailto:piratebase@sina.com>Struct chen</a> * */ public abstract class PacketOutputStream extends OutputStream { /** The buffer in which we store our packet data. */ protected ByteBuffer _buffer; /** The default initial size of the internal buffer. */ protected static final int INITIAL_BUFFER_SIZE = 32; public PacketOutputStream () { _buffer = ByteBuffer.allocate(INITIAL_BUFFER_SIZE); initHeader(); } /** * Writes the specified byte to this output stream. * * @param b the byte to be written. */ public void write (int b) { try { _buffer.put((byte)b); } catch (BufferOverflowException boe) { expand(1); _buffer.put((byte)b); } } /** * Writes <code>len</code> bytes from the specified byte array * starting at offset <code>off</code> to this output stream. * * @param b the data. * @param off the start offset in the data. * @param len the number of bytes to write. */ public void write (byte[] b, int off, int len) { // sanity check the arguments if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } try { _buffer.put(b, off, len); } catch (BufferOverflowException boe) { expand(len); _buffer.put(b, off, len); } } /** * Expands our buffer to accomodate the specified capacity. */ protected final void expand (int needed) { int ocapacity = _buffer.capacity(); int ncapacity = _buffer.position() + needed; if (ncapacity > ocapacity) { // increase the buffer size in large increments ncapacity = Math.max(ocapacity << 1, ncapacity); ByteBuffer newbuf = ByteBuffer.allocate(ncapacity); newbuf.put((ByteBuffer)_buffer.flip()); _buffer = newbuf; } } /** * Writes the packet length to the beginning of our buffer and returns * it for writing to the appropriate channel. This should be followed * by a call to {@link #resetPacket} when the packet has been written. */ public abstract ByteBuffer returnPacketBuffer (); /** * Resets our internal buffer and prepares to write a new packet. */ public void resetPacket () { _buffer.clear(); initHeader(); } protected abstract void initHeader(); }