/**
* Copyright (c) 2002-2011 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j 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, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.ha;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.charset.Charset;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferFactory;
import org.jboss.netty.buffer.ChannelBufferIndexFinder;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
public class ChunkingChannelBuffer implements ChannelBuffer
{
static final byte CONTINUATION_LAST = 0;
static final byte CONTINUATION_MORE = 1;
private ChannelBuffer buffer;
private final Channel channel;
private final int capacity;
private int continuationPosition;
public ChunkingChannelBuffer( ChannelBuffer buffer, Channel channel, int capacity )
{
this.buffer = buffer;
this.channel = channel;
this.capacity = capacity;
addRoomForContinuationHeader();
}
private void addRoomForContinuationHeader()
{
continuationPosition = writerIndex();
buffer.writeByte( CONTINUATION_LAST );
}
private void setContinuation( byte value )
{
buffer.setByte( continuationPosition, value );
}
public ChannelBufferFactory factory()
{
return buffer.factory();
}
public int capacity()
{
return buffer.capacity();
}
public ByteOrder order()
{
return buffer.order();
}
public boolean isDirect()
{
return buffer.isDirect();
}
public int readerIndex()
{
return buffer.readerIndex();
}
public void readerIndex( int readerIndex )
{
buffer.readerIndex( readerIndex );
}
public int writerIndex()
{
return buffer.writerIndex();
}
public void writerIndex( int writerIndex )
{
buffer.writerIndex( writerIndex );
}
public void setIndex( int readerIndex, int writerIndex )
{
buffer.setIndex( readerIndex, writerIndex );
}
public int readableBytes()
{
return buffer.readableBytes();
}
public int writableBytes()
{
return buffer.writableBytes();
}
public boolean readable()
{
return buffer.readable();
}
public boolean writable()
{
return buffer.writable();
}
public void clear()
{
buffer.clear();
}
public void markReaderIndex()
{
buffer.markReaderIndex();
}
public void resetReaderIndex()
{
buffer.resetReaderIndex();
}
public void markWriterIndex()
{
buffer.markWriterIndex();
}
public void resetWriterIndex()
{
buffer.resetWriterIndex();
}
public void discardReadBytes()
{
buffer.discardReadBytes();
}
public void ensureWritableBytes( int writableBytes )
{
buffer.ensureWritableBytes( writableBytes );
}
public byte getByte( int index )
{
return buffer.getByte( index );
}
public short getUnsignedByte( int index )
{
return buffer.getUnsignedByte( index );
}
public short getShort( int index )
{
return buffer.getShort( index );
}
public int getUnsignedShort( int index )
{
return buffer.getUnsignedShort( index );
}
public int getMedium( int index )
{
return buffer.getMedium( index );
}
public int getUnsignedMedium( int index )
{
return buffer.getUnsignedMedium( index );
}
public int getInt( int index )
{
return buffer.getInt( index );
}
public long getUnsignedInt( int index )
{
return buffer.getUnsignedInt( index );
}
public long getLong( int index )
{
return buffer.getLong( index );
}
public char getChar( int index )
{
return buffer.getChar( index );
}
public float getFloat( int index )
{
return buffer.getFloat( index );
}
public double getDouble( int index )
{
return buffer.getDouble( index );
}
public void getBytes( int index, ChannelBuffer dst )
{
buffer.getBytes( index, dst );
}
public void getBytes( int index, ChannelBuffer dst, int length )
{
buffer.getBytes( index, dst, length );
}
public void getBytes( int index, ChannelBuffer dst, int dstIndex, int length )
{
buffer.getBytes( index, dst, dstIndex, length );
}
public void getBytes( int index, byte[] dst )
{
buffer.getBytes( index, dst );
}
public void getBytes( int index, byte[] dst, int dstIndex, int length )
{
buffer.getBytes( index, dst, dstIndex, length );
}
public void getBytes( int index, ByteBuffer dst )
{
buffer.getBytes( index, dst );
}
public void getBytes( int index, OutputStream out, int length ) throws IOException
{
buffer.getBytes( index, out, length );
}
public int getBytes( int index, GatheringByteChannel out, int length ) throws IOException
{
return buffer.getBytes( index, out, length );
}
public void setByte( int index, int value )
{
buffer.setByte( index, value );
}
public void setShort( int index, int value )
{
buffer.setShort( index, value );
}
public void setMedium( int index, int value )
{
buffer.setMedium( index, value );
}
public void setInt( int index, int value )
{
buffer.setInt( index, value );
}
public void setLong( int index, long value )
{
buffer.setLong( index, value );
}
public void setChar( int index, int value )
{
buffer.setChar( index, value );
}
public void setFloat( int index, float value )
{
buffer.setFloat( index, value );
}
public void setDouble( int index, double value )
{
buffer.setDouble( index, value );
}
public void setBytes( int index, ChannelBuffer src )
{
buffer.setBytes( index, src );
}
public void setBytes( int index, ChannelBuffer src, int length )
{
buffer.setBytes( index, src, length );
}
public void setBytes( int index, ChannelBuffer src, int srcIndex, int length )
{
buffer.setBytes( index, src, srcIndex, length );
}
public void setBytes( int index, byte[] src )
{
buffer.setBytes( index, src );
}
public void setBytes( int index, byte[] src, int srcIndex, int length )
{
buffer.setBytes( index, src, srcIndex, length );
}
public void setBytes( int index, ByteBuffer src )
{
buffer.setBytes( index, src );
}
public int setBytes( int index, InputStream in, int length ) throws IOException
{
return buffer.setBytes( index, in, length );
}
public int setBytes( int index, ScatteringByteChannel in, int length ) throws IOException
{
return buffer.setBytes( index, in, length );
}
public void setZero( int index, int length )
{
buffer.setZero( index, length );
}
public byte readByte()
{
return buffer.readByte();
}
public short readUnsignedByte()
{
return buffer.readUnsignedByte();
}
public short readShort()
{
return buffer.readShort();
}
public int readUnsignedShort()
{
return buffer.readUnsignedShort();
}
public int readMedium()
{
return buffer.readMedium();
}
public int readUnsignedMedium()
{
return buffer.readUnsignedMedium();
}
public int readInt()
{
return buffer.readInt();
}
public long readUnsignedInt()
{
return buffer.readUnsignedInt();
}
public long readLong()
{
return buffer.readLong();
}
public char readChar()
{
return buffer.readChar();
}
public float readFloat()
{
return buffer.readFloat();
}
public double readDouble()
{
return buffer.readDouble();
}
public ChannelBuffer readBytes( int length )
{
return buffer.readBytes( length );
}
public ChannelBuffer readBytes( ChannelBufferIndexFinder indexFinder )
{
return buffer.readBytes( indexFinder );
}
public ChannelBuffer readSlice( int length )
{
return buffer.readSlice( length );
}
public ChannelBuffer readSlice( ChannelBufferIndexFinder indexFinder )
{
return buffer.readSlice( indexFinder );
}
public void readBytes( ChannelBuffer dst )
{
buffer.readBytes( dst );
}
public void readBytes( ChannelBuffer dst, int length )
{
buffer.readBytes( dst, length );
}
public void readBytes( ChannelBuffer dst, int dstIndex, int length )
{
buffer.readBytes( dst, dstIndex, length );
}
public void readBytes( byte[] dst )
{
buffer.readBytes( dst );
}
public void readBytes( byte[] dst, int dstIndex, int length )
{
buffer.readBytes( dst, dstIndex, length );
}
public void readBytes( ByteBuffer dst )
{
buffer.readBytes( dst );
}
public void readBytes( OutputStream out, int length ) throws IOException
{
buffer.readBytes( out, length );
}
public int readBytes( GatheringByteChannel out, int length ) throws IOException
{
return buffer.readBytes( out, length );
}
public void skipBytes( int length )
{
buffer.skipBytes( length );
}
public int skipBytes( ChannelBufferIndexFinder indexFinder )
{
return buffer.skipBytes( indexFinder );
}
private void sendChunkIfNeeded( int bytesPlus )
{
if ( writerIndex()+bytesPlus >= capacity )
{
setContinuation( CONTINUATION_MORE );
writeCurrentChunk();
// TODO Reuse buffers?
buffer = ChannelBuffers.dynamicBuffer();
addRoomForContinuationHeader();
}
}
private void writeCurrentChunk()
{
channel.write( buffer );
}
public void done()
{
if ( writable() )
{
writeCurrentChunk();
}
}
public void writeByte( int value )
{
sendChunkIfNeeded( 1 );
buffer.writeByte( value );
}
public void writeShort( int value )
{
sendChunkIfNeeded( 2 );
buffer.writeShort( value );
}
public void writeMedium( int value )
{
sendChunkIfNeeded( 4 );
buffer.writeMedium( value );
}
public void writeInt( int value )
{
sendChunkIfNeeded( 4 );
buffer.writeInt( value );
}
public void writeLong( long value )
{
sendChunkIfNeeded( 8 );
buffer.writeLong( value );
}
public void writeChar( int value )
{
sendChunkIfNeeded( 2 );
buffer.writeChar( value );
}
public void writeFloat( float value )
{
sendChunkIfNeeded( 8 );
buffer.writeFloat( value );
}
public void writeDouble( double value )
{
sendChunkIfNeeded( 8 );
buffer.writeDouble( value );
}
public void writeBytes( ChannelBuffer src )
{
sendChunkIfNeeded( src.capacity() );
buffer.writeBytes( src );
}
public void writeBytes( ChannelBuffer src, int length )
{
sendChunkIfNeeded( length );
buffer.writeBytes( src, length );
}
public void writeBytes( ChannelBuffer src, int srcIndex, int length )
{
sendChunkIfNeeded( length );
buffer.writeBytes( src, srcIndex, length );
}
public void writeBytes( byte[] src )
{
sendChunkIfNeeded( src.length );
buffer.writeBytes( src );
}
public void writeBytes( byte[] src, int srcIndex, int length )
{
sendChunkIfNeeded( length );
buffer.writeBytes( src, srcIndex, length );
}
public void writeBytes( ByteBuffer src )
{
sendChunkIfNeeded( src.limit() );
buffer.writeBytes( src );
}
public int writeBytes( InputStream in, int length ) throws IOException
{
sendChunkIfNeeded( length );
return buffer.writeBytes( in, length );
}
public int writeBytes( ScatteringByteChannel in, int length ) throws IOException
{
sendChunkIfNeeded( length );
return buffer.writeBytes( in, length );
}
public void writeZero( int length )
{
sendChunkIfNeeded( length );
buffer.writeZero( length );
}
public int indexOf( int fromIndex, int toIndex, byte value )
{
return buffer.indexOf( fromIndex, toIndex, value );
}
public int indexOf( int fromIndex, int toIndex, ChannelBufferIndexFinder indexFinder )
{
return buffer.indexOf( fromIndex, toIndex, indexFinder );
}
public int bytesBefore( byte value )
{
return buffer.bytesBefore( value );
}
public int bytesBefore( ChannelBufferIndexFinder indexFinder )
{
return buffer.bytesBefore( indexFinder );
}
public int bytesBefore( int length, byte value )
{
return buffer.bytesBefore( length, value );
}
public int bytesBefore( int length, ChannelBufferIndexFinder indexFinder )
{
return buffer.bytesBefore( length, indexFinder );
}
public int bytesBefore( int index, int length, byte value )
{
return buffer.bytesBefore( index, length, value );
}
public int bytesBefore( int index, int length, ChannelBufferIndexFinder indexFinder )
{
return buffer.bytesBefore( index, length, indexFinder );
}
public ChannelBuffer copy()
{
return buffer.copy();
}
public ChannelBuffer copy( int index, int length )
{
return buffer.copy( index, length );
}
public ChannelBuffer slice()
{
return buffer.slice();
}
public ChannelBuffer slice( int index, int length )
{
return buffer.slice( index, length );
}
public ChannelBuffer duplicate()
{
return buffer.duplicate();
}
public ByteBuffer toByteBuffer()
{
return buffer.toByteBuffer();
}
public ByteBuffer toByteBuffer( int index, int length )
{
return buffer.toByteBuffer( index, length );
}
public ByteBuffer[] toByteBuffers()
{
return buffer.toByteBuffers();
}
public ByteBuffer[] toByteBuffers( int index, int length )
{
return buffer.toByteBuffers( index, length );
}
public boolean hasArray()
{
return buffer.hasArray();
}
public byte[] array()
{
return buffer.array();
}
public int arrayOffset()
{
return buffer.arrayOffset();
}
public String toString( Charset charset )
{
return buffer.toString( charset );
}
public String toString( int index, int length, Charset charset )
{
return buffer.toString( index, length, charset );
}
public String toString( String charsetName )
{
return buffer.toString( charsetName );
}
public String toString( String charsetName, ChannelBufferIndexFinder terminatorFinder )
{
return buffer.toString( charsetName, terminatorFinder );
}
public String toString( int index, int length, String charsetName )
{
return buffer.toString( index, length, charsetName );
}
public String toString( int index, int length, String charsetName,
ChannelBufferIndexFinder terminatorFinder )
{
return buffer.toString( index, length, charsetName, terminatorFinder );
}
public int compareTo( ChannelBuffer buffer )
{
return buffer.compareTo( buffer );
}
public String toString()
{
return buffer.toString();
}
}