/* * @(#)BufferedConnectionAdapter.java 1.4 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * 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 * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.cdc.io; import java.io.*; /** * This class adds read buffering to the * <code>ConnectionBaseAdapter</code>. * <p> * Implements {@link InputStream#available()}, however a subclass must * specify a buffer size greater than 0 and override * {@link #readBytesNonBlocking(byte[], int, int)} in order to for available * to work properly. */ public abstract class BufferedConnectionAdapter extends ConnectionBaseAdapter { /** * The end of file flag. */ protected boolean eof; /** * The internal buffer array where the data is stored. * When necessary, it may be replaced by another array * of a different size. */ protected byte buf[]; /** * The index one greater than the index of the last valid * byte in the buffer. * This value is always in the range * <code>0</code> through <code>buf.length</code>; * elements <code>buf[0]</code> through <code>buf[count-1] * </code>contain buffered input data obtained * from the underlying input stream. */ protected int count; /** * The current position in the buffer. This is the index * of the next character to be read from the * <code>buf</code> array. * <p> * This value is always in the range <code>0</code> * through <code>count</code>. If it is less * than <code>count</code>, then <code>buf[pos]</code> * is the next byte to be supplied as input; * if it is equal to <code>count</code>, then * the next <code>read</code> or <code>skip</code> * operation will require more bytes to be * read from the contained input stream. */ protected int pos; /** * Initializes the connection. * * @param sizeOfBuffer size of the internal buffer or 0 for no buffer */ protected BufferedConnectionAdapter(int sizeOfBuffer) { if (sizeOfBuffer > 0) { buf = new byte[sizeOfBuffer]; } } /** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes, blocks until at least one byte is available. * <p> * Do not use this method if <code>openInputStream</code> has been called * since the input stream may be buffering data. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ public int readBytes(byte b[], int off, int len) throws IOException { if (count == 0) { if (eof) { return -1; } if (buf == null || len >= buf.length) { return nonBufferedRead(b, off, len); } else { int res = nonBufferedRead(buf, 0, buf.length); pos = 0; if (res <= 0) { return res; } else { count = res; } } } if (len > count) { len = count; } System.arraycopy(buf, pos, b, off, len); count -= len; pos += len; return len; }; /** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes, but does not block if no bytes available. A subclass * should implement this to so the available method on the InputStream * will be useful. * Sets the <code>eof</code> field of the connection when the native read * returns -1. * <p> * The <code>readBytesNonBlocking</code> method of * <code>ConnectionBaseAdapter</code> does nothing and returns 0. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ protected int readBytesNonBlocking(byte b[], int off, int len) throws IOException { return 0; } /** * Returns the number of bytes that can be read (or skipped over) from * this input stream without blocking by the next caller of a method for * this input stream. The next caller might be the same thread or * another thread. * * <p>The <code>available</code> method always returns <code>0</code> if * {@link #readBytesNonBlocking(byte[], int, int)} is * not overridden by the subclass or there is not buffer. * * @return the number of bytes that can be read from this input stream * without blocking. * @exception IOException if an I/O error occurs. */ public int available() throws IOException { int bytesRead; if (buf == null) { return 0; } if (count > 0) { return count; } bytesRead = readBytesNonBlocking(buf, 0, buf.length); if (bytesRead == -1) { return 0; } /* * Reset the current buffer position and count of bytes * available. These variables must be reset to match * the processing in readBytes. */ pos = 0; count = bytesRead; return count; } /** * Reads up to <code>len</code> bytes of data from the input stream into * an array of bytes, blocks until at least one byte is available. * Sets the <code>eof</code> field of the connection when there is * no more data in the stream to read. * * @param b the buffer into which the data is read. * @param off the start offset in array <code>b</code> * at which the data is written. * @param len the maximum number of bytes to read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the stream has been reached. * @exception IOException if an I/O error occurs. */ protected abstract int nonBufferedRead(byte b[], int off, int len) throws IOException; }