Java tutorial
/** * 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("test.stream"); * PacketOutputStream cos = new PacketOutputStream(fos); * CapturePacket packet = //gotten from live network or file * cos.writePacket(packet); * cos.close(); * * FileInputStream fis = new FileInputStream("test.stream"); * 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()); } } }