org.jnetstream.capture.PacketInputStream.java Source code

Java tutorial

Introduction

Here is the source code for org.jnetstream.capture.PacketInputStream.java

Source

/**
 * Copyright (C) 2007 Sly Technologies, Inc. This library is free software; you
 * can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version. This
 * library 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 Lesser General Public License for more
 * details. You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
package org.jnetstream.capture;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.sql.Timestamp;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>
 * A <code>PacketInputStream</code> deserializes <code>Packet</code> objects
 * into <code>DeserializedPacket</code> objects previously written using a
 * <code>PacketOutputStream</code>. <code>DeserializedPacket</code>
 * interface is a subclass of <code>CapturePacket</code> which adds several
 * new methods that contain information about the serialization process.
 * </p>
 * <p>
 * Here is an example:
 * 
 * <pre>
 * 
 * FileOutputStream fos = new FileOutputStream(&quot;test.stream&quot;);
 * PacketOutputStream cos = new PacketOutputStream(fos);
 * CapturePacket packet = //gotten from live network or file 
 *     cos.writePacket(packet);
 * cos.close();
 * 
 * FileInputStream fis = new FileInputStream(&quot;test.stream&quot;);
 * PacketInputStream cis = new PacketInputStream(fis);
 * packet = cis.readPacket();
 * cis.close();
 * 
 * </pre>
 * 
 * </p>
 * 
 * @author Mark Bednarczyk
 * @author Sly Technologies, Inc.
 */
public class PacketInputStream extends InputStream implements CapturePacketInput<CapturePacket>, Closeable {

    private static final Log logger = LogFactory.getLog(PacketInputStream.class);

    protected ObjectInputStream in;

    /**
     * <P>
     * Provide a way for subclasses that are completely reimplementing
     * CapturePacketInputStream to not have to allocate private data just used by
     * this implementation of CapturePacketInputStream.
     * </P>
     */
    protected PacketInputStream() {
        super();
    }

    /**
     * Creates an ObjectInputStream that reads from the specified InputStream. A
     * serialization stream header is read from the stream and verified. This
     * constructor will block until the corresponding CapturePacketOutputStream
     * has written and flushed the header.
     * 
     * @param in
     *          input stream to read from
     * @throws IOException
     *           any usual I/O errors
     */
    public PacketInputStream(InputStream in) throws IOException {
        this.in = new ObjectInputStream(in);

    }

    /**
     * Gets the number of bytes available for read without blocking the operation.
     * 
     * @return number of byte available for immediate read
     * @exception IOException
     *              any IO errors
     * @see java.io.InputStream#available()
     */
    @Override
    public int available() throws IOException {
        return in.available();
    }

    /**
     * Closes this and the underlying input stream.
     * 
     * @exception IOException
     *              any IO errors
     * @see java.io.InputStream#close()
     */
    @Override
    public void close() throws IOException {
        in.close();
    }

    /**
     * Marks the current position in this input stream. A subsequent call to the
     * reset method repositions this stream at the last marked position so that
     * subsequent reads re-read the same bytes. The readlimit arguments tells this
     * input stream to allow that many bytes to be read before the mark position
     * gets invalidated. The general contract of mark is that, if the method
     * markSupported returns true, the stream somehow remembers all the bytes read
     * after the call to mark and stands ready to supply those same bytes again if
     * and whenever the method reset is called. However, the stream is not
     * required to remember any data at all if more than readlimit bytes are read
     * from the stream before reset is called. The mark method of InputStream does
     * nothing.
     * 
     * @param readlimit
     *          the maximum limit of bytes that can be read before the mark
     *          position becomes invalid.
     * @see java.io.InputStream#mark(int)
     */
    @Override
    public synchronized void mark(int readlimit) {
        in.mark(readlimit);
    }

    /**
     * Tests if this input stream supports the mark and reset methods. Whether or
     * not mark and reset are supported is an invariant property of a particular
     * input stream instance. The markSupported method of InputStream returns
     * false.
     * 
     * @return true if this stream instance supports the mark and reset methods;
     *         false otherwise.
     * @see java.io.InputStream#markSupported()
     */
    @Override
    public boolean markSupported() {
        return in.markSupported();
    }

    /**
     * <P>
     * Reads up to len bytes of data from the input stream into an array of bytes.
     * An attempt is made to read as many as len bytes, but a smaller number may
     * be read. The number of bytes actually read is returned as an integer.
     * </P>
     * <P>
     * This method blocks until input data is available, end of file is detected,
     * or an exception is thrown.
     * </P>
     * <P>
     * If b is null, a NullPointerException is thrown.
     * </P>
     * <P>
     * If off is negative, or len is negative, or off+len is greater than the
     * length of the array b, then an IndexOutOfBoundsException is thrown.
     * </P>
     * <P>
     * If len is zero, then no bytes are read and 0 is returned; otherwise, there
     * is an attempt to read at least one byte. If no byte is available because
     * the stream is at end of file, the value -1 is returned; otherwise, at least
     * one byte is read and stored into b.
     * </P>
     * <P>
     * The first byte read is stored into element b[off], the next one into
     * b[off+1], and so on. The number of bytes read is, at most, equal to len.
     * Let k be the number of bytes actually read; these bytes will be stored in
     * elements b[off] through b[off+k-1], leaving elements b[off+k] through
     * b[off+len-1] unaffected.
     * </P>
     * <P>
     * In every case, elements b[0] through b[off] and elements b[off+len] through
     * b[b.length-1] are unaffected.
     * </P>
     * <P>
     * If the first byte cannot be read for any reason other than end of file,
     * then an IOException is thrown. In particular, an IOException is thrown if
     * the input stream has been closed.
     * </P>
     * <P>
     * The read(b, off, len) method for class InputStream simply calls the method
     * read() repeatedly. If the first such call results in an IOException, that
     * exception is returned from the call to the read(b, off, len) method. If any
     * subsequent call to read() results in a IOException, the exception is caught
     * and treated as if it were end of file; the bytes read up to that point are
     * stored into b and the number of bytes read before the exception occurred is
     * returned. Subclasses are encouraged to provide a more efficient
     * implementation of this method.
     * </P>
     * 
     * @param b
     *          the buffer into which the data is read
     * @param off
     *          the start offset in array b 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 -1 if there is
     *         no more data because the end of the stream has been reached
     * @exception IOException
     *              any IO errors
     * @exception NullPointerException
     *              if b is null
     * @see java.io.InputStream#read(byte[], int, int)
     */
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    /**
     * <P>
     * Reads some number of bytes from the input stream and stores them into the
     * buffer array b. The number of bytes actually read is returned as an
     * integer. This method blocks until input data is available, end of file is
     * detected, or an exception is thrown.
     * </P>
     * <P>
     * If b is null, a NullPointerException is thrown. If the length of b is zero,
     * then no bytes are read and 0 is returned; otherwise, there is an attempt to
     * read at least one byte. If no byte is available because the stream is at
     * end of file, the value -1 is returned; otherwise, at least one byte is read
     * and stored into b.
     * </P>
     * <P>
     * The first byte read is stored into element b[0], the next one into b[1],
     * and so on. The number of bytes read is, at most, equal to the length of b.
     * Let k be the number of bytes actually read; these bytes will be stored in
     * elements b[0] through b[k-1], leaving elements b[k] through b[b.length-1]
     * unaffected.
     * </P>
     * <P>
     * If the first byte cannot be read for any reason other than end of file,
     * then an IOException is thrown. In particular, an IOException is thrown if
     * the input stream has been closed.
     * </P>
     * <P>
     * The read(b) method for class InputStream has the same effect as:
     * <CODE>read(b,
     * 0, b.length)</code>
     * </P>
     */
    @Override
    public int read(byte[] b) throws IOException {
        return in.read(b);
    }

    /**
     * Repositions this stream to the position at the time the mark method was
     * last called on this input stream. The general contract of reset is:
     * <UL>
     * <LI>If the method markSupported returns true, then:
     * <UL>
     * <LI> If the method mark has not been called since the stream was created,
     * or the number of bytes read from the stream since mark was last called is
     * larger than the argument to mark at that last call, then an IOException
     * might be thrown.
     * <LI>If such an IOException is not thrown, then the stream is reset to a
     * state such that all the bytes read since the most recent call to mark (or
     * since the start of the file, if mark has not been called) will be
     * resupplied to subsequent callers of the read method, followed by any bytes
     * that otherwise would have been the next input data as of the time of the
     * call to reset.
     * </UL>
     * <LI>If the method markSupported returns false, then:
     * <UL>
     * <LI>The call to reset may throw an IOException.
     * <LI>If an IOException is not thrown, then the stream is reset to a fixed
     * state that depends on the particular type of the input stream and how it
     * was created. The bytes that will be supplied to subsequent callers of the
     * read method depend on the particular type of the input stream.
     * </UL>
     * </UL>
     * The method reset for class InputStream does nothing except throw an
     * IOException.
     * 
     * @see java.io.InputStream#mark(int)
     */
    @Override
    public synchronized void reset() throws IOException {
        in.reset();
    }

    /**
     * Skips over and discards n bytes of data from this input stream. The skip
     * method may, for a variety of reasons, end up skipping over some smaller
     * number of bytes, possibly 0. This may result from any of a number of
     * conditions; reaching end of file before n bytes have been skipped is only
     * one possibility. The actual number of bytes skipped is returned. If n is
     * negative, no bytes are skipped. The skip method of InputStream creates a
     * byte array and then repeatedly reads into it until n bytes have been read
     * or the end of the stream has been reached. Subclasses are encouraged to
     * provide a more efficient implementation of this method.
     * 
     * @param n
     *          the number of bytes to be skipped.
     * @return the actual number of bytes skipped.
     * @Throws IOException -
     *           if an I/O error occurs.
     * @see java.io.InputStream#skip(long)
     */
    @Override
    public long skip(long n) throws IOException {
        return in.skip(n);
    }

    /*
     * <P>Reads the next byte of data from the input stream. The value byte is
     * returned as an int in the range 0 to 255. If no byte is available because
     * the end of the stream has been reached, the value -1 is returned. This
     * method blocks until input data is available, the end of the stream is
     * detected, or an exception is thrown.</P> <P>A subclass must provide an
     * implementation of this method.</P> @returns the next byte of data, or -1
     * if the end of the stream is reached. @throws IOException - if an I/O error
     * occurs.
     * 
     * @see java.io.InputStream#read()
     */
    @Override
    public int read() throws IOException {
        return in.read();
    }

    /**
     * Deserializes a packet from the underlying input stream that was previously
     * serialized by a corresponding PacketOutputStream object.
     * 
     * @return a deserialized a packet
     * @see com.slytechs.capture.stream.CapturePacketInput#readCapturePacket()
     */
    public DeserializedPacket readPacket() throws IOException {
        try {
            DeserializedPacket packet = (DeserializedPacket) in.readObject();

            packet.setDeserializedTimestamp(new Timestamp(System.currentTimeMillis()));

            return packet;
        } catch (ClassNotFoundException e) {
            logger.error("Can not deserialize a packet from InputStream " + e.getMessage());
            throw new IOException("Can not deserialize a packet from InputStrea " + e.getMessage());
        }
    }
}