package filerogue; import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.util.logging.Level; import java.util.logging.Logger; /** * This class reads byte data sent from a NBObjectOutputStream * (possibly in many discrete chunks) and deserializes the object * only after all the data for the object has been received. */ public class NBObjectInputStream extends ObjectInputStream { private static final Logger logger = Logger.getLogger( "global" ); private final static int HEADER_SIZE = 4; // number of bytes in header private final static int MAX_OBJ_SIZE = 2 * 1024 * 1024; // max object size is 2 MB InputStream inStream; // underlying input stream byte[] bHeader = new byte[ HEADER_SIZE ], // buffer for header data bObjBuffer; // buffer for incoming object int iHeaderBytesRead, // number of header bytes read iObjectBytesRead, // number of object bytes read iCount, // counts number of bytes per block read iObjSize; // size of the object in bytes int iLastCount; // size of last chunk that was read in // speed test values int iTestObjSize = -1; long lTestTime = -1; int iTestBps = -1; static boolean blocking = true; public NBObjectInputStream( InputStream in ) throws IOException { super(); inStream = in; } public static void setBlocking( boolean b ) { blocking = b; } /** * Attempts to read an object (or partial object) from the stream. * This routine will return null until an entire object has been * received and deserialized. * * @return object */ public final Object readObjectOverride() throws IOException, ClassNotFoundException { if ( !blocking && lTestTime == -1 ) { lTestTime = System.currentTimeMillis(); // see if we have are currently trying to read an object size header } if ( iHeaderBytesRead < HEADER_SIZE ) { // attempt to fill in the header buffer iCount = inStream.read( bHeader, iHeaderBytesRead, HEADER_SIZE - iHeaderBytesRead ); if ( lTestTime == -1 ) { lTestTime = System.currentTimeMillis(); // no more data } if ( iCount == -1 ) { throw new EOFException( "End of stream detected" ); } // inc. header bytes read iHeaderBytesRead += iCount; // if we just completed reading the header size, create a new byte array to buffer the incoming object data if ( iHeaderBytesRead == HEADER_SIZE ) { // convert the 4-byte header into an int iObjSize = ( ( ( int ) bHeader[ 0 ] & 255 ) << 24 ) + ( ( ( int ) bHeader[ 1 ] & 255 ) << 16 ) + ( ( ( int ) bHeader[ 2 ] & 255 ) << 8 ) + ( ( ( int ) bHeader[ 3 ] & 255 ) ); if ( iObjSize < 0 || iObjSize > MAX_OBJ_SIZE ) { throw new IOException( "Illegal object size reported in header" ); } if ( Thread.currentThread()instanceof ThreadState ) { ( ( ThreadState ) Thread.currentThread() ).setState( "Allocating Object Byte Array: " + iObjSize + " bytes" ); } bObjBuffer = new byte[ iObjSize ]; // initialize the object bytes counter iObjectBytesRead = 0; } } // see if we have a complete size header (ie, time to read the actual object data) if ( iHeaderBytesRead == HEADER_SIZE ) { if ( Thread.currentThread()instanceof ThreadState ) { ( ( ThreadState ) Thread.currentThread() ).setState( "Reading object" ); } // read in as much of the object as is available in the stream (and will fit in the buffer) iCount = inStream.read( bObjBuffer, iObjectBytesRead, iObjSize - iObjectBytesRead ); iLastCount = iCount; // no more data if ( iCount == -1 ) { throw new EOFException( "End of stream detected!" ); } // inc. object bytes counter iObjectBytesRead += iCount; // see if we have a complete object if ( iObjectBytesRead == iObjSize ) { // do speed test stuff lTestTime = System.currentTimeMillis() - lTestTime; if ( lTestTime < 500 ) { lTestTime = 500; } if ( iObjSize > iTestObjSize ) { iTestObjSize = iObjSize; iTestBps = ( int ) ( iObjSize * 1000 / lTestTime ); } lTestTime = -1; if ( iObjSize > 100000 ) { logger.log( Level.FINE, "New Large Object Received: " + iObjSize + " bytes" ); } if ( Thread.currentThread()instanceof ThreadState ) { ( ( ThreadState ) Thread.currentThread() ).setState( "Deserializing object" ); } // deserialize the object long lDeserialize = System.currentTimeMillis(); Object obj = new ObjectInputStream( new ByteArrayInputStream( bObjBuffer ) ).readObject(); lDeserialize = System.currentTimeMillis() - lDeserialize; if ( lDeserialize > 1000 ) { logger.log( Level.INFO, "LONG Object Deserialization: " + obj + ", " + iObjSize + " bytes (" + lDeserialize + " ms)" ); // reset the header counter for the next object along the stream } iHeaderBytesRead = 0; // return our new baby return obj; } } // if we got this far, we're still waiting on stuff return null; } public int getBps() { return iTestBps; } }