Old object streaming code goes bye-bye.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1604 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: BooleanFieldMarshaller.java,v 1.7 2002/07/17 23:05:27 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class BooleanFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Boolean.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeBoolean(field.getBoolean(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setBoolean(obj, in.readBoolean());
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// $Id: ByteArrayFieldMarshaller.java,v 1.2 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ByteArrayFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return (new byte[0]).getClass();
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
byte[] value = (byte[])field.get(obj);
|
||||
// we convert null arrays to zero length arrays
|
||||
if (value == null) {
|
||||
out.writeInt(0);
|
||||
|
||||
} else {
|
||||
out.writeInt(value.length);
|
||||
out.write(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
int vlength = in.readInt();
|
||||
byte[] value = new byte[vlength];
|
||||
if (in.read(value) != vlength) {
|
||||
throw new EOFException();
|
||||
}
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: ByteFieldMarshaller.java,v 1.2 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ByteFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Byte.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeByte(field.getByte(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setByte(obj, in.readByte());
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// $Id: DSetFieldMarshaller.java,v 1.5 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
public class DSetFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return DSet.class;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
DSet value = (DSet)field.get(obj);
|
||||
// we freak out if our set is null
|
||||
if (value == null) {
|
||||
throw new IllegalAccessException("No set instance to marshall!");
|
||||
}
|
||||
value.writeTo(out);
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
DSet value = new DSet();
|
||||
value.readFrom(in);
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: DoubleFieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class DoubleFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Double.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeDouble(field.getDouble(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setDouble(obj, in.readDouble());
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// $Id: FieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* A field marshaller knows how to marshall and unmarshall a particular
|
||||
* data type. It is called upon to do the actual on the wire
|
||||
* encoding/decoding of a field.
|
||||
*/
|
||||
public interface FieldMarshaller
|
||||
{
|
||||
public Class getFieldType ();
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException;
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException;
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
//
|
||||
// $Id: FieldMarshallerRegistry.java,v 1.16 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.io.Streamable;
|
||||
|
||||
/**
|
||||
* Field marshaller instances are registered for each type of field that
|
||||
* is supported in a distributed object.
|
||||
*/
|
||||
public class FieldMarshallerRegistry
|
||||
{
|
||||
/**
|
||||
* Returns a field marshaller that can marshall and unmarshall the
|
||||
* specified type of field. If no marshaller is registered for that
|
||||
* field type, an illegal argument exception will be thrown.
|
||||
* Distributed objects must not contain fields that cannot be
|
||||
* transmitted on the wire.
|
||||
*/
|
||||
public static FieldMarshaller getMarshaller (Field field)
|
||||
{
|
||||
Class clazz = field.getType();
|
||||
FieldMarshaller marsh = (FieldMarshaller)_registry.get(clazz);
|
||||
|
||||
// if we don't have a marshaller registered for this specific
|
||||
// class, see if the class is an instance of streamable in which
|
||||
// case we stick the streamable marshaller into the registry for
|
||||
// this class
|
||||
if (marsh == null) {
|
||||
if (Streamable.class.isAssignableFrom(clazz)) {
|
||||
marsh = _streamableMarsh;
|
||||
_registry.put(clazz, marsh);
|
||||
} else if (STREAMARRAY_CLASS.isAssignableFrom(clazz)) {
|
||||
marsh = _streamarrayMarsh;
|
||||
_registry.put(clazz, marsh);
|
||||
}
|
||||
}
|
||||
|
||||
// if we still don't have a marshaller, we're out of luck
|
||||
if (marsh == null) {
|
||||
String errmsg = "No field marshaller registered for fields " +
|
||||
"of type " + clazz.getName() + ".";
|
||||
throw new IllegalArgumentException(errmsg);
|
||||
}
|
||||
|
||||
return marsh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified field marshaller as the one to use for
|
||||
* fields of the specified class. This assumes that the field
|
||||
* marshaller implementation provides a prototype field of the type it
|
||||
* knows how to marshall by the name of <code>prototype</code>.
|
||||
*
|
||||
* @param clazz the field marshaller class to be registered.
|
||||
*/
|
||||
protected static void registerMarshaller (Class clazz)
|
||||
{
|
||||
try {
|
||||
FieldMarshaller fm = (FieldMarshaller)clazz.newInstance();
|
||||
_registry.put(fm.getFieldType(), fm);
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to register field marshaller " +
|
||||
"[class=" + clazz.getName() + "].");
|
||||
Log.logStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** A mapping of classes to marshallers. */
|
||||
protected static Hashtable _registry = new Hashtable();
|
||||
|
||||
/** Used for marshalling instances of {@link Streamable}. */
|
||||
protected static FieldMarshaller _streamableMarsh =
|
||||
new StreamableFieldMarshaller();
|
||||
|
||||
/** Used for marshalling arrays of {@link Streamable}. */
|
||||
protected static FieldMarshaller _streamarrayMarsh =
|
||||
new StreamableArrayFieldMarshaller();
|
||||
|
||||
/** Used to identify streamable array instances. */
|
||||
protected static final Class STREAMARRAY_CLASS =
|
||||
(new Streamable[0]).getClass();
|
||||
|
||||
static {
|
||||
// register our field marshallers
|
||||
registerMarshaller(BooleanFieldMarshaller.class);
|
||||
registerMarshaller(ByteFieldMarshaller.class);
|
||||
registerMarshaller(ShortFieldMarshaller.class);
|
||||
registerMarshaller(IntFieldMarshaller.class);
|
||||
registerMarshaller(IntegerFieldMarshaller.class);
|
||||
registerMarshaller(LongFieldMarshaller.class);
|
||||
registerMarshaller(FloatFieldMarshaller.class);
|
||||
registerMarshaller(DoubleFieldMarshaller.class);
|
||||
registerMarshaller(StringFieldMarshaller.class);
|
||||
registerMarshaller(ByteArrayFieldMarshaller.class);
|
||||
registerMarshaller(IntArrayFieldMarshaller.class);
|
||||
registerMarshaller(StringArrayFieldMarshaller.class);
|
||||
registerMarshaller(OidListFieldMarshaller.class);
|
||||
registerMarshaller(DSetFieldMarshaller.class);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: FloatFieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class FloatFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Float.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeFloat(field.getFloat(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setFloat(obj, in.readFloat());
|
||||
}
|
||||
}
|
||||
@@ -1,258 +0,0 @@
|
||||
//
|
||||
// $Id: FramedInputStream.java,v 1.10 2002/06/18 22:07:38 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
import com.threerings.presents.Log;
|
||||
|
||||
/**
|
||||
* The framed input stream reads input that was framed by a framing output
|
||||
* stream. Framing in this case simply means writing the length of the
|
||||
* frame followed by the data associated with the frame so that an entire
|
||||
* frame can be loaded from the network layer before any higher layer
|
||||
* attempts to process it. Additionally, any failure in decoding a frame
|
||||
* won't result in the entire stream being skewed due to the remainder of
|
||||
* the undecoded frame remaining in the input stream.
|
||||
*
|
||||
* <p>The framed input stream reads an entire frame worth of data into its
|
||||
* internal buffer when <code>readFrame()</code> is called. It then
|
||||
* behaves as if this is the only data available on the stream (meaning
|
||||
* that when the data in the frame is exhausted, it will behave as if the
|
||||
* end of the stream has been reached). The buffer can only contain a
|
||||
* single frame at a time, so any data left over from a previous frame
|
||||
* will disappear when <code>readFrame()</code> is called again.
|
||||
*
|
||||
* <p><em>Note:</em> The framing input stream does not synchronize reads
|
||||
* from its internal buffer. It is intended to only be accessed from a
|
||||
* single thread.
|
||||
*
|
||||
* <p>Implementation note: maybe this should derive from
|
||||
* <code>FilterInputStream</code> and be tied to a single
|
||||
* <code>InputStream</code> for its lifetime.
|
||||
*/
|
||||
public class FramedInputStream extends InputStream
|
||||
{
|
||||
public FramedInputStream ()
|
||||
{
|
||||
_header = new byte[HEADER_SIZE];
|
||||
_buffer = new byte[INITIAL_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a frame from the provided input stream, or appends to a
|
||||
* partially read frame. Appends the read data to the existing data
|
||||
* available via the framed input stream's read methods. If the entire
|
||||
* frame data is not yet available, <code>readFrame</code> will return
|
||||
* false, otherwise true.
|
||||
*
|
||||
* <p> The code assumes that it will be able to read the entire frame
|
||||
* header in a single read. The header is only four bytes and should
|
||||
* always arrive at the beginning of a packet, so unless something is
|
||||
* very funky with the networking layer, this should be a safe
|
||||
* assumption.
|
||||
*
|
||||
* @return true if the entire frame has been read, false if the buffer
|
||||
* contains only a partial frame.
|
||||
*/
|
||||
public boolean readFrame (InputStream source)
|
||||
throws IOException
|
||||
{
|
||||
// if the buffer currently contains a complete frame, that means
|
||||
// we're not halfway through reading a frame and that we can start
|
||||
// anew.
|
||||
if (_count == _length) {
|
||||
// read in the frame length
|
||||
int got = source.read(_header, 0, HEADER_SIZE);
|
||||
if (got < 0) {
|
||||
throw new EOFException();
|
||||
|
||||
} else if (got == 0) {
|
||||
// TBD: don't log this for now, but look into it later
|
||||
// Log.info("Woke up to read data, but there ain't none. Sigh.");
|
||||
return false;
|
||||
|
||||
} else if (got < HEADER_SIZE) {
|
||||
String errmsg = "FramedInputStream does not support " +
|
||||
"partially reading the header. Needed " + HEADER_SIZE +
|
||||
" bytes, got " + got + " bytes.";
|
||||
throw new RuntimeException(errmsg);
|
||||
}
|
||||
|
||||
// now that we've read our new frame length, we can clear out
|
||||
// any prior data
|
||||
_pos = 0;
|
||||
_count = 0;
|
||||
|
||||
// decode the frame length
|
||||
_length = (_header[0] & 0xFF) << 24;
|
||||
_length += (_header[1] & 0xFF) << 16;
|
||||
_length += (_header[2] & 0xFF) << 8;
|
||||
_length += (_header[3] & 0xFF);
|
||||
|
||||
// if necessary, expand our buffer to accomodate the frame
|
||||
if (_length > _buffer.length) {
|
||||
// increase the buffer size in large increments
|
||||
_buffer = new byte[Math.max(_buffer.length << 1, _length)];
|
||||
}
|
||||
}
|
||||
|
||||
// read the data into the buffer
|
||||
int got = source.read(_buffer, _count, _length-_count);
|
||||
if (got < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
_count += got;
|
||||
|
||||
return (_count == _length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream. The value byte
|
||||
* is returned as an <code>int</code> in the range <code>0</code> to
|
||||
* <code>255</code>. If no byte is available because the end of the
|
||||
* stream has been reached, the value <code>-1</code> is returned.
|
||||
*
|
||||
* <p>This <code>read</code> method cannot block.
|
||||
*
|
||||
* @return the next byte of data, or <code>-1</code> if the end of the
|
||||
* stream has been reached.
|
||||
*/
|
||||
public int read ()
|
||||
{
|
||||
return (_pos < _count) ? (_buffer[_pos++] & 0xFF) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to <code>len</code> bytes of data into an array of bytes
|
||||
* from this input stream. If <code>pos</code> equals
|
||||
* <code>count</code>, then <code>-1</code> is returned to indicate
|
||||
* end of file. Otherwise, the number <code>k</code> of bytes read is
|
||||
* equal to the smaller of <code>len</code> and
|
||||
* <code>count-pos</code>. If <code>k</code> is positive, then bytes
|
||||
* <code>buf[pos]</code> through <code>buf[pos+k-1]</code> are copied
|
||||
* into <code>b[off]</code> through <code>b[off+k-1]</code> in the
|
||||
* manner performed by <code>System.arraycopy</code>. The value
|
||||
* <code>k</code> is added into <code>pos</code> and <code>k</code> is
|
||||
* returned.
|
||||
*
|
||||
* <p>This <code>read</code> method cannot block.
|
||||
*
|
||||
* @param b the buffer into which the data is read.
|
||||
* @param off the start offset of the data.
|
||||
* @param len the maximum number of bytes 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.
|
||||
*/
|
||||
public int read (byte[] b, int off, int len)
|
||||
{
|
||||
// sanity check the arguments
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
// figure out how much data we'll return
|
||||
if (_pos >= _count) {
|
||||
// if they asked to read zero bytes and we have no bytes
|
||||
// remaining; we're supposed to return 0 rather than EOF
|
||||
return (len == 0) ? 0 : -1;
|
||||
}
|
||||
if (_pos + len > _count) {
|
||||
len = _count - _pos;
|
||||
}
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// copy and advance
|
||||
System.arraycopy(_buffer, _pos, b, off, len);
|
||||
_pos += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skips <code>n</code> bytes of input from this input stream. Fewer
|
||||
* bytes might be skipped if the end of the input stream is reached.
|
||||
* The actual number <code>k</code> of bytes to be skipped is equal to
|
||||
* the smaller of <code>n</code> and <code>count-pos</code>. The value
|
||||
* <code>k</code> is added into <code>pos</code> and <code>k</code> is
|
||||
* returned.
|
||||
*
|
||||
* @param n the number of bytes to be skipped.
|
||||
*
|
||||
* @return the actual number of bytes skipped.
|
||||
*/
|
||||
public long skip (long n)
|
||||
{
|
||||
if (_pos + n > _count) {
|
||||
n = _count - _pos;
|
||||
}
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
_pos += n;
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read from this input stream
|
||||
* without blocking. The value returned is <code>count - pos</code>,
|
||||
* which is the number of bytes remaining to be read from the input
|
||||
* buffer.
|
||||
*
|
||||
* @return the number of bytes remaining to be read from the buffered
|
||||
* frames.
|
||||
*/
|
||||
public int available ()
|
||||
{
|
||||
return _count - _pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns false as framed input streams do not support
|
||||
* marking.
|
||||
*/
|
||||
public boolean markSupported ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing, as marking is not supported.
|
||||
*/
|
||||
public void mark (int readAheadLimit)
|
||||
{
|
||||
// not supported; do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer to the beginning of the buffered frames.
|
||||
*/
|
||||
public void reset ()
|
||||
{
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
protected byte[] _header;
|
||||
protected int _length;
|
||||
|
||||
protected byte[] _buffer;
|
||||
protected int _pos;
|
||||
protected int _count;
|
||||
|
||||
/** The size of the frame header (a 32-bit integer). */
|
||||
protected static final int HEADER_SIZE = 4;
|
||||
|
||||
/** The default initial size of the internal buffer. */
|
||||
protected static final int INITIAL_BUFFER_SIZE = 32;
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
//
|
||||
// $Id: FramingOutputStream.java,v 1.4 2001/10/11 04:07:52 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The framing output stream accumulates output into a byte array just
|
||||
* like the byte array output stream, but can then be instructed to send
|
||||
* its contents down another output stream, prefixed by the length
|
||||
* (written as an integer) of those contents. It does this efficiently so
|
||||
* that data is copied as little as possible and so that the output stream
|
||||
* to which the data is written need not be buffered because the framed
|
||||
* output is written in a single call to <code>write()</code>.
|
||||
*
|
||||
* <p><em>Note:</em> The framing output stream does not synchronize writes
|
||||
* to its internal buffer. It is intended to only be accessed from a
|
||||
* single thread.
|
||||
*
|
||||
* <p>Implementation note: maybe this should derive from
|
||||
* <code>FilterOutputStream</code> and be tied to a single
|
||||
* <code>OutputStream</code> for its lifetime.
|
||||
*/
|
||||
public class FramingOutputStream extends OutputStream
|
||||
{
|
||||
public FramingOutputStream ()
|
||||
{
|
||||
_buffer = new byte[INITIAL_BUFFER_SIZE];
|
||||
_count = 4; // leave room for the frame size at the beginning
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this framing output stream.
|
||||
*
|
||||
* @param b the byte to be written.
|
||||
*/
|
||||
public void write (int b)
|
||||
{
|
||||
// expand our buffer if necessary
|
||||
int newcount = _count + 1;
|
||||
if (newcount > _buffer.length) {
|
||||
// increase the buffer size in large increments
|
||||
byte[] newbuf = new byte[Math.max(_buffer.length << 1, newcount)];
|
||||
System.arraycopy(_buffer, 0, newbuf, 0, _count);
|
||||
_buffer = newbuf;
|
||||
}
|
||||
|
||||
// copy and advance
|
||||
_buffer[_count] = (byte)b;
|
||||
_count = newcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes <code>len</code> bytes from the specified byte array
|
||||
* starting at offset <code>off</code> to this framing output stream.
|
||||
*
|
||||
* @param b the data.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of bytes to write.
|
||||
*/
|
||||
public void write (byte[] b, int off, int len)
|
||||
{
|
||||
// sanity check the arguments
|
||||
if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// expand the buffer if necessary
|
||||
int newcount = _count + len;
|
||||
if (newcount > _buffer.length) {
|
||||
// increase the buffer size in large increments
|
||||
byte[] newbuf = new byte[Math.max(_buffer.length << 1, newcount)];
|
||||
System.arraycopy(_buffer, 0, newbuf, 0, _count);
|
||||
_buffer = newbuf;
|
||||
}
|
||||
|
||||
// copy and advance
|
||||
System.arraycopy(b, off, _buffer, _count, len);
|
||||
_count = newcount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of this framing output stream to the target
|
||||
* output stream, prefixed by an integer with value equal to the
|
||||
* number of bytes written folling that integer. It then resets the
|
||||
* framing output stream to prepare for another framed message.
|
||||
*/
|
||||
public void writeFrameAndReset (OutputStream target)
|
||||
throws IOException
|
||||
{
|
||||
// prefix the frame with the byte count in network byte order (the
|
||||
// format used by DataOutputStream)
|
||||
int count = _count - 4;
|
||||
_buffer[0] = (byte)((count >>> 24) & 0xFF);
|
||||
_buffer[1] = (byte)((count >>> 16) & 0xFF);
|
||||
_buffer[2] = (byte)((count >>> 8) & 0xFF);
|
||||
_buffer[3] = (byte)((count >>> 0) & 0xFF);
|
||||
|
||||
// write the data
|
||||
target.write(_buffer, 0, _count);
|
||||
|
||||
// reset our internal buffer
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset ()
|
||||
{
|
||||
// leave room for the frame size at the beginning
|
||||
_count = 4;
|
||||
}
|
||||
|
||||
protected byte[] _buffer;
|
||||
protected int _count;
|
||||
|
||||
/** The default initial size of the internal buffer. */
|
||||
protected static final int INITIAL_BUFFER_SIZE = 32;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// $Id: IntArrayFieldMarshaller.java,v 1.4 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class IntArrayFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return (new int[0]).getClass();
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
int[] value = (int[])field.get(obj);
|
||||
// we convert null arrays to zero length arrays
|
||||
if (value == null) {
|
||||
out.writeInt(0);
|
||||
|
||||
} else {
|
||||
out.writeInt(value.length);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
out.writeInt(value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
int[] value = new int[in.readInt()];
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
value[i] = in.readInt();
|
||||
}
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: IntFieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class IntFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Integer.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeInt(field.getInt(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setInt(obj, in.readInt());
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// $Id: IntegerFieldMarshaller.java,v 1.2 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class IntegerFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Integer.class;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
Integer value = (Integer)field.get(obj);
|
||||
// we convert null integers to zero
|
||||
out.writeInt((value == null) ? 0 : value.intValue());
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.set(obj, new Integer(in.readInt()));
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: LongFieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class LongFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Long.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeLong(field.getLong(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setLong(obj, in.readLong());
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
//
|
||||
// $Id: Marshaller.java,v 1.10 2002/02/19 03:30:40 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
import com.threerings.presents.io.ObjectStreamException;
|
||||
|
||||
/**
|
||||
* The marshaller inspects the class with which it is constructed and
|
||||
* caches the reflection information it needs to marshall and unmarshall
|
||||
* instances of that class.
|
||||
*/
|
||||
public class Marshaller
|
||||
{
|
||||
/**
|
||||
* Writes the supplied object instance out to the supplied data output
|
||||
* stream, using a {@link Marshaller} for field marshalling.
|
||||
*/
|
||||
public static void writeObject (DataOutputStream out, Object object)
|
||||
throws IOException
|
||||
{
|
||||
getMarshaller(object).writeTo(out, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the fields of the supplied object from the supplied data
|
||||
* input stream, using a {@link Marshaller} for field unmarshalling.
|
||||
*/
|
||||
public static void readObject (DataInputStream in, Object object)
|
||||
throws IOException
|
||||
{
|
||||
getMarshaller(object).readFrom(in, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the marshaller for objects of this object's class, creating
|
||||
* one if necessary.
|
||||
*/
|
||||
protected static synchronized Marshaller getMarshaller (Object object)
|
||||
{
|
||||
Class clazz = object.getClass();
|
||||
Marshaller marsh = (Marshaller)_marshcache.get(clazz);
|
||||
if (marsh == null) {
|
||||
marsh = new Marshaller(clazz);
|
||||
_marshcache.put(clazz, marsh);
|
||||
}
|
||||
return marsh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a marshaller for the specified class. Introspection is
|
||||
* done during construct time to speed up subsequent marshalling and
|
||||
* unmarshalling.
|
||||
*/
|
||||
protected Marshaller (Class clazz)
|
||||
{
|
||||
// we introspect on the class and cache the public data members
|
||||
Field[] fields = clazz.getFields();
|
||||
ArrayList flist = new ArrayList();
|
||||
|
||||
// we only want non-static, non-final, non-transient fields
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
int mods = fields[i].getModifiers();
|
||||
if ((mods & Modifier.PUBLIC) == 0 ||
|
||||
(mods & Modifier.STATIC) != 0 ||
|
||||
(mods & Modifier.TRANSIENT) != 0 ||
|
||||
(mods & Modifier.FINAL) != 0) {
|
||||
continue;
|
||||
}
|
||||
flist.add(fields[i]);
|
||||
}
|
||||
|
||||
// create an array of the fields we want
|
||||
_fields = new Field[flist.size()];
|
||||
flist.toArray(_fields);
|
||||
|
||||
// sort the fields so that they are written and read in the same
|
||||
// order on all VMs
|
||||
Arrays.sort(_fields, FIELD_COMP);
|
||||
|
||||
// now select field marshallers for each of the fields based on
|
||||
// their type
|
||||
_marshallers = new FieldMarshaller[_fields.length];
|
||||
for (int i = 0; i < _fields.length; i++) {
|
||||
_marshallers[i] =
|
||||
FieldMarshallerRegistry.getMarshaller(_fields[i]);
|
||||
// Log.info("Assigned [field=" + _fields[i] +
|
||||
// ", marshaller=" + _marshallers[i] + "].");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out all of the fields of the specified distributed object to
|
||||
* the supplied data output stream.
|
||||
*/
|
||||
public void writeTo (DataOutputStream out, Object obj)
|
||||
throws IOException
|
||||
{
|
||||
// we simply iterate over our marshallers, writing each field
|
||||
// out in succession
|
||||
for (int i = 0; i < _fields.length; i++) {
|
||||
try {
|
||||
_marshallers[i].writeTo(out, _fields[i], obj);
|
||||
|
||||
} catch (IllegalAccessException iae) {
|
||||
// this shouldn't happen because we only attempt to marshall
|
||||
// public fields, but we'll pass it on none the less
|
||||
String errmsg = "Unable to marshall obj field " +
|
||||
"[field=" + _fields[i].getName() +
|
||||
", obj=" + obj + "].";
|
||||
throw new ObjectStreamException(errmsg, iae);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in all of the fields of the specified distributed object from
|
||||
* the supplied data input stream.
|
||||
*/
|
||||
public void readFrom (DataInputStream in, Object obj)
|
||||
throws IOException
|
||||
{
|
||||
// we simply iterate over our marshallers, reading each field in
|
||||
// in succession
|
||||
for (int i = 0; i < _fields.length; i++) {
|
||||
try {
|
||||
_marshallers[i].readFrom(in, _fields[i], obj);
|
||||
|
||||
} catch (IllegalAccessException iae) {
|
||||
// this shouldn't happen because we only attempt to
|
||||
// unmarshall public fields, but we'll pass it on anyway
|
||||
String errmsg = "Unable to unmarshall obj field " +
|
||||
"[field=" + _fields[i].getName() +
|
||||
", obj=" + obj + "].";
|
||||
Log.logStackTrace(iae);
|
||||
throw new ObjectStreamException(errmsg, iae);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to sort object fields into a predictable order.
|
||||
*/
|
||||
protected static class FieldComparator implements Comparator
|
||||
{
|
||||
public int compare (Object o1, Object o2)
|
||||
{
|
||||
return ((Field)o1).getName().compareTo(((Field)o2).getName());
|
||||
}
|
||||
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
// we don't care about comparing this comparator to others
|
||||
return obj == this;
|
||||
}
|
||||
}
|
||||
|
||||
/** The fields that are marshalled by this marshaller. */
|
||||
protected Field[] _fields;
|
||||
|
||||
/** The field marshallers that are used to marshall the fields. */
|
||||
protected FieldMarshaller[] _marshallers;
|
||||
|
||||
/** A table of instantiated marshallers for our various marshalled
|
||||
* classes. */
|
||||
protected static HashMap _marshcache = new HashMap();
|
||||
|
||||
/** We use this to sort the fields into a predictable order. */
|
||||
protected static final FieldComparator FIELD_COMP = new FieldComparator();
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
//
|
||||
// $Id: ObjectStreamException.java,v 1.6 2002/04/01 16:49:26 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.apache.commons.lang.exception.Nestable;
|
||||
import org.apache.commons.lang.exception.NestableDelegate;
|
||||
|
||||
/**
|
||||
* The object stream exception is used to communicate an error in
|
||||
* processing a typed object stream. As any error is fatal, we don't
|
||||
* differentiate exceptions with separate classes, but instead communicate
|
||||
* the nature of the error in the exception message with the assumption
|
||||
* that the caller will want to raise holy hell in every case.
|
||||
*/
|
||||
public class ObjectStreamException
|
||||
extends IOException implements Nestable
|
||||
{
|
||||
/**
|
||||
* Constructs an object stream exception with the specified message.
|
||||
*/
|
||||
public ObjectStreamException (String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an object stream exception with the specified message
|
||||
* and causing exception.
|
||||
*/
|
||||
public ObjectStreamException (String message, Throwable cause)
|
||||
{
|
||||
super(message);
|
||||
_cause = cause;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Throwable getCause ()
|
||||
{
|
||||
return _cause;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String getMessage ()
|
||||
{
|
||||
StringBuffer msg = new StringBuffer();
|
||||
|
||||
// include our message if we have one
|
||||
String ourMsg = super.getMessage();
|
||||
if (ourMsg != null) {
|
||||
msg.append(ourMsg);
|
||||
}
|
||||
|
||||
// and append the message from our causing exception if we've got
|
||||
// one of those
|
||||
if (_cause != null) {
|
||||
String causeMsg = _cause.getMessage();
|
||||
if (causeMsg != null) {
|
||||
if (ourMsg != null) {
|
||||
msg.append(": ");
|
||||
}
|
||||
msg.append(causeMsg);
|
||||
}
|
||||
}
|
||||
|
||||
return (msg.length() > 0 ? msg.toString() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the stack trace of this exception the the standar error
|
||||
* stream.
|
||||
*/
|
||||
public void printStackTrace ()
|
||||
{
|
||||
_delegate.printStackTrace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the stack trace of this exception to the specified print
|
||||
* stream.
|
||||
*
|
||||
* @param out {@link PrintStream} to use for output.
|
||||
*/
|
||||
public void printStackTrace (PrintStream out)
|
||||
{
|
||||
_delegate.printStackTrace(out);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void printStackTrace (PrintWriter out)
|
||||
{
|
||||
_delegate.printStackTrace(out);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public final void printPartialStackTrace (PrintWriter out)
|
||||
{
|
||||
super.printStackTrace(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* The helper instance which contains much of the code which we
|
||||
* delegate to.
|
||||
*/
|
||||
protected NestableDelegate _delegate = new NestableDelegate(this);
|
||||
|
||||
/**
|
||||
* Holds the reference to the exception or error that caused this
|
||||
* exception to be thrown.
|
||||
*/
|
||||
protected Throwable _cause = null;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
//
|
||||
// $Id: OidListFieldMarshaller.java,v 1.5 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.threerings.presents.dobj.OidList;
|
||||
|
||||
public class OidListFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return OidList.class;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
OidList value = (OidList)field.get(obj);
|
||||
// we convert null oid lists to empty oid lists
|
||||
if (value == null) {
|
||||
value = new OidList();
|
||||
}
|
||||
value.writeTo(out);
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
OidList value = new OidList();
|
||||
value.readFrom(in);
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// $Id: ShortFieldMarshaller.java,v 1.7 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class ShortFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Short.TYPE;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
out.writeShort(field.getShort(obj));
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.setShort(obj, in.readShort());
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// $Id: SimpleStreamableObject.java,v 1.2 2002/03/26 22:56:54 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* A simple streamable object uses the {@link Marshaller} class to stream
|
||||
* its fields and provides a simple mechanism for objects to make
|
||||
* themselves streamable without having to write any code. They simply
|
||||
* declare all fields to be streamed as public data members (marking
|
||||
* public fields as <code>transient</code> that should not be streamed)
|
||||
* and ensure that the fields are all valid streamable types (see {@link
|
||||
* FieldMarshallerRegistry}).
|
||||
*/
|
||||
public class SimpleStreamableObject
|
||||
implements Streamable
|
||||
{
|
||||
// documentation inherited from interface
|
||||
public void writeTo (DataOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
Marshaller.writeObject(out, this);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void readFrom (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
Marshaller.readObject(in, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this instance.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
StringBuffer buf = new StringBuffer("[");
|
||||
toString(buf);
|
||||
return buf.append("]").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes can override this method and add non-public members
|
||||
* to the <code>toString()</code> output.
|
||||
*/
|
||||
protected void toString (StringBuffer buf)
|
||||
{
|
||||
StringUtil.fieldsToString(buf, this);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
//
|
||||
// $Id: Streamable.java,v 1.2 2001/10/11 04:07:52 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
/**
|
||||
* A streamable is an object that knows how to read and write itself on a
|
||||
* stream. We are obliged to reimplement an object serialization framework
|
||||
* rather than use the one provided by Java because we're interested in
|
||||
* taking maximal advantage of situations where we know the types of
|
||||
* objects that are being streamed and in those cases we avoid writing
|
||||
* type information for the objects and only write the values. In other
|
||||
* cases, we assign unique codes to object classes (see {@link
|
||||
* TypedObject}) to minimize the network footprint of the serialized
|
||||
* objects.
|
||||
*/
|
||||
public interface Streamable
|
||||
{
|
||||
/**
|
||||
* Writes all of the members of this object to the supplied data
|
||||
* output stream.
|
||||
*/
|
||||
public void writeTo (DataOutputStream out)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Reads all of the members of this object in from the supplied data
|
||||
* input stream.
|
||||
*/
|
||||
public void readFrom (DataInputStream in)
|
||||
throws IOException;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
//
|
||||
// $Id: StreamableArrayFieldMarshaller.java,v 1.2 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.threerings.presents.io.Streamable;
|
||||
|
||||
public class StreamableArrayFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return (new Streamable[0]).getClass();
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
Streamable[] values = (Streamable[])field.get(obj);
|
||||
|
||||
// in order to make use of the general purpose streamable
|
||||
// serialization routines, we have to have a non-null array, so we
|
||||
// create a zero length array if our field value is null
|
||||
if (values == null) {
|
||||
values = (Streamable[])Array.newInstance(
|
||||
field.getType().getComponentType(), 0);
|
||||
}
|
||||
|
||||
StreamableUtil.writeStreamables(out, values);
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
// read and set
|
||||
field.set(obj, StreamableUtil.readStreamables(in));
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
//
|
||||
// $Id: StreamableFieldMarshaller.java,v 1.6 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.samskivert.io.NestableIOException;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.io.Streamable;
|
||||
|
||||
public class StreamableFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return Streamable.class;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
Streamable value = (Streamable)field.get(obj);
|
||||
if (value == null) {
|
||||
out.writeUTF("");
|
||||
} else {
|
||||
out.writeUTF(value.getClass().getName());
|
||||
value.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
try {
|
||||
Streamable value = null;
|
||||
String scnm = in.readUTF();
|
||||
|
||||
// instantiate and unserialize the streamable if we actually
|
||||
// have a value
|
||||
if (!StringUtil.blank(scnm)) {
|
||||
Class sclass = Class.forName(scnm);
|
||||
// create a new instance into which to unmarshall the field
|
||||
value = (Streamable)sclass.newInstance();
|
||||
// unserialize it
|
||||
value.readFrom(in);
|
||||
}
|
||||
|
||||
// and set the value in the object
|
||||
field.set(obj, value);
|
||||
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Unable to instantiate streamable " +
|
||||
"[field=" + field + ", object=" + obj + "]";
|
||||
throw new NestableIOException(errmsg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
//
|
||||
// $Id: StreamableUtil.java,v 1.3 2002/03/20 23:08:22 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import com.samskivert.io.NestableIOException;
|
||||
import com.samskivert.util.ListUtil;
|
||||
|
||||
/**
|
||||
* Utility functions useful for {@link Streamable} implementations.
|
||||
*/
|
||||
public class StreamableUtil
|
||||
{
|
||||
/**
|
||||
* Writes the supplied int array to the data output stream.
|
||||
*/
|
||||
public static void writeInts (DataOutputStream out, int[] values)
|
||||
throws IOException
|
||||
{
|
||||
int vcount = values.length;
|
||||
out.writeInt(vcount);
|
||||
for (int i = 0; i < vcount; i++) {
|
||||
out.writeInt(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of ints from the data input stream that was
|
||||
* previously written via {@link #writeInts}.
|
||||
*/
|
||||
public static int[] readInts (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
int vcount = in.readInt();
|
||||
int[] values = new int[vcount];
|
||||
for (int i = 0; i < vcount; i++) {
|
||||
values[i] = in.readInt();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied string array to the data output stream.
|
||||
*/
|
||||
public static void writeStrings (DataOutputStream out, String[] values)
|
||||
throws IOException
|
||||
{
|
||||
int vcount = values.length;
|
||||
out.writeInt(vcount);
|
||||
for (int i = 0; i < vcount; i++) {
|
||||
out.writeUTF(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of strings from the data input stream that was
|
||||
* previously written via {@link #writeStrings}.
|
||||
*/
|
||||
public static String[] readStrings (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
int vcount = in.readInt();
|
||||
String[] values = new String[vcount];
|
||||
for (int i = 0; i < vcount; i++) {
|
||||
values[i] = in.readUTF();
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the supplied streamable array to the data output stream. The
|
||||
* array cannot be null, but can be of zero length.
|
||||
*/
|
||||
public static void writeStreamables (
|
||||
DataOutputStream out, Streamable[] values)
|
||||
throws IOException
|
||||
{
|
||||
// create a list used to map class names to class ids
|
||||
Object[] cnames = new Object[DEFAULT_SIZE];
|
||||
|
||||
// seed it with the component type of the array (which we write
|
||||
// out first so that we can recreate the array on the other side)
|
||||
String cname = values.getClass().getComponentType().getName();
|
||||
cnames[0] = cname;
|
||||
out.writeUTF(cname);
|
||||
|
||||
// write out the size of the list
|
||||
int size = (values == null) ? 0 : values.length;
|
||||
out.writeInt(size);
|
||||
|
||||
// write out each of the list elements
|
||||
short nextIdx = 1;
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
// get the next streamable to write out
|
||||
Streamable s = values[ii];
|
||||
|
||||
// if this index is empty, write -1 as the class identifier to
|
||||
// indicate such
|
||||
if (s == null) {
|
||||
out.writeShort(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// look up the class id
|
||||
cname = s.getClass().getName();
|
||||
short cidx = (short)ListUtil.indexOfEqual(cnames, cname);
|
||||
if (cidx == -1) {
|
||||
// store this class name to class id mapping
|
||||
cidx = nextIdx++;
|
||||
cnames = ListUtil.add(cnames, cidx, cname);
|
||||
|
||||
// write out the class id and class name
|
||||
out.writeShort(cidx);
|
||||
out.writeUTF(cname);
|
||||
|
||||
} else {
|
||||
// we need only write out the class id
|
||||
out.writeShort(cidx);
|
||||
}
|
||||
|
||||
// write out the object itself
|
||||
s.writeTo(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of streamables from the data input stream that was
|
||||
* previously written via {@link #writeStreamables}.
|
||||
*/
|
||||
public static Streamable[] readStreamables (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
// read in the component type and array size
|
||||
String ctype = in.readUTF();
|
||||
int size = in.readInt();
|
||||
Streamable[] values = null;
|
||||
|
||||
// create the target array
|
||||
try {
|
||||
values = (Streamable[])
|
||||
Array.newInstance(Class.forName(ctype), size);
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Unable to instantiate streamable array " +
|
||||
"[ctype=" + ctype + "]";
|
||||
throw new NestableIOException(errmsg, e);
|
||||
}
|
||||
|
||||
// create a list used to map class ids to class names
|
||||
Object[] cnames = new Object[DEFAULT_SIZE];
|
||||
// seed our class names with the component type
|
||||
cnames[0] = ctype;
|
||||
|
||||
// read in each of the list elements
|
||||
for (int ii = 0; ii < size; ii++) {
|
||||
// read the class id number
|
||||
short cidx = in.readShort();
|
||||
|
||||
// if the class identifier is -1, that means this is a null
|
||||
// element
|
||||
if (cidx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// look up the class name
|
||||
String cname = (cidx > cnames.length - 1) ? null :
|
||||
(String)cnames[cidx];
|
||||
if (cname == null) {
|
||||
// store this class id to class name mapping
|
||||
cname = in.readUTF();
|
||||
cnames = ListUtil.add(cnames, cidx, cname);
|
||||
}
|
||||
|
||||
try {
|
||||
// instantiate the streamable object
|
||||
Class clazz = Class.forName(cname);
|
||||
Streamable s = (Streamable)clazz.newInstance();
|
||||
// read in the object itself
|
||||
s.readFrom(in);
|
||||
// and add it to the list
|
||||
values[ii] = s;
|
||||
|
||||
} catch (Exception e) {
|
||||
String errmsg = "Error instantiating streamable array " +
|
||||
"element [ctype=" + ctype + ", index=" + ii +
|
||||
", etype=" + cname + "]";
|
||||
throw new NestableIOException(errmsg, e);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/** The default size of the class name lists used when serializing or
|
||||
* unserializing the list. */
|
||||
protected static final int DEFAULT_SIZE = 8;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// $Id: StringArrayFieldMarshaller.java,v 1.5 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class StringArrayFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return (new String[0]).getClass();
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
String[] value = (String[])field.get(obj);
|
||||
// we convert null string arrays to zero length arrays
|
||||
if (value == null) {
|
||||
out.writeInt(0);
|
||||
|
||||
} else {
|
||||
out.writeInt(value.length);
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
out.writeUTF((value[i] == null) ? "" : value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
String[] value = new String[in.readInt()];
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
value[i] = in.readUTF();
|
||||
}
|
||||
field.set(obj, value);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// $Id: StringFieldMarshaller.java,v 1.8 2002/07/17 23:05:28 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class StringFieldMarshaller implements FieldMarshaller
|
||||
{
|
||||
/** Returns the sort of field that we marshall. */
|
||||
public Class getFieldType ()
|
||||
{
|
||||
return String.class;
|
||||
}
|
||||
|
||||
public void writeTo (DataOutputStream out, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
String value = (String)field.get(obj);
|
||||
// we convert null strings to empty strings
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
out.writeUTF(value);
|
||||
}
|
||||
|
||||
public void readFrom (DataInputStream in, Field field, Object obj)
|
||||
throws IOException, IllegalAccessException
|
||||
{
|
||||
field.set(obj, in.readUTF());
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// $Id: TypedObject.java,v 1.5 2001/10/11 04:07:52 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
/**
|
||||
* A typed object is one that is associated with a particular type code.
|
||||
* The type code can be communicated on the wire and used by the receiving
|
||||
* end to instantiate the proper typed object class for decoding (which is
|
||||
* done by the <code>TypedObjectFactory</code>).
|
||||
*
|
||||
* @see TypedObjectFactory
|
||||
*/
|
||||
public interface TypedObject extends Streamable
|
||||
{
|
||||
/**
|
||||
* Each typed object class must associate itself with a type value via
|
||||
* the <code>TypedObjectFactory</code> so that the factory can
|
||||
* instantiate the proper <code>TypedObject</code> derived class when
|
||||
* decoding an incoming message.
|
||||
*
|
||||
* @return The type code associated with this object.
|
||||
*/
|
||||
public short getType ();
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
//
|
||||
// $Id: TypedObjectFactory.java,v 1.8 2001/10/16 16:44:20 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.threerings.presents.Log;
|
||||
|
||||
/**
|
||||
* The encodable factory is used to unserialize encodable object instances
|
||||
* from a stream. It maintains a mapping of encodable object classes to
|
||||
* identifier codes which it uses to determine what sort of object is on
|
||||
* the stream. The encodable mechanism is used to associate a particular
|
||||
* class with some compact code that can be transmitted on the wire to
|
||||
* identify that class.
|
||||
*/
|
||||
public class TypedObjectFactory
|
||||
{
|
||||
/**
|
||||
* Reads (unserializes) a typed object from the supplied data input
|
||||
* stream.
|
||||
*
|
||||
* @return The unserialized typed object instance.
|
||||
*/
|
||||
public static TypedObject readFrom (DataInputStream din)
|
||||
throws IOException, ObjectStreamException
|
||||
{
|
||||
// first determine the type of the incoming object
|
||||
short type = din.readShort();
|
||||
|
||||
// now instantiate the proper object and decode the remainder
|
||||
TypedObject msg = newObjectByType(type);
|
||||
msg.readFrom(din);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes (serializes) a typed object to the supplied data output
|
||||
* stream.
|
||||
*/
|
||||
public static void writeTo (DataOutputStream dout, TypedObject tobj)
|
||||
throws IOException
|
||||
{
|
||||
// first write the type of the object
|
||||
dout.writeShort(tobj.getType());
|
||||
// then write the object itself
|
||||
tobj.writeTo(dout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the supplied class with the specified type code. If a
|
||||
* class is already registered with that type code a runtime exception
|
||||
* will be thrown so that the proper freaking out can occur.
|
||||
*/
|
||||
public static void registerClass (short type, Class clazz)
|
||||
{
|
||||
Short key = new Short(type);
|
||||
|
||||
// make sure no funny business is afoot
|
||||
if (_classes.containsKey(key)) {
|
||||
Class incumbent = (Class)_classes.get(key);
|
||||
String errmsg = "Cannot register " + clazz.getName() +
|
||||
" as type " + type + " because " + incumbent.getName() +
|
||||
" is already registered with that type.";
|
||||
throw new RuntimeException(errmsg);
|
||||
}
|
||||
|
||||
// set up the mapping
|
||||
_classes.put(key, clazz);
|
||||
}
|
||||
|
||||
protected static TypedObject newObjectByType (short type)
|
||||
throws ObjectStreamException
|
||||
{
|
||||
Class clazz = (Class)_classes.get(new Short(type));
|
||||
if (clazz == null) {
|
||||
String errmsg = "Unknown object type: " + type;
|
||||
throw new ObjectStreamException(errmsg);
|
||||
}
|
||||
|
||||
try {
|
||||
return (TypedObject)clazz.newInstance();
|
||||
} catch (Throwable t) {
|
||||
String errmsg = "Unable to instantiate typed object " +
|
||||
"[class=" + clazz.getName() + "]";
|
||||
throw new ObjectStreamException(errmsg, t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Our type to class mapping table. */
|
||||
protected static HashMap _classes = new HashMap();
|
||||
|
||||
// register our typed object
|
||||
static {
|
||||
TypedObjectRegistry.registerTypedObjects();
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
//
|
||||
// $Id: TypedObjectRegistry.java,v 1.11 2002/03/21 01:57:40 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import com.threerings.presents.dobj.*;
|
||||
import com.threerings.presents.net.*;
|
||||
|
||||
/**
|
||||
* The registry provides a single place where all typed objects that are
|
||||
* exchanged between the client and the server can be registered with the
|
||||
* typed object factory.
|
||||
*/
|
||||
public class TypedObjectRegistry
|
||||
{
|
||||
/**
|
||||
* Must be called once by the client and the server to ensure that all
|
||||
* typed objects are registered with the typed object system.
|
||||
*/
|
||||
public static void registerTypedObjects ()
|
||||
{
|
||||
// register our upstream message classes
|
||||
TypedObjectFactory.registerClass(AuthRequest.TYPE,
|
||||
AuthRequest.class);
|
||||
TypedObjectFactory.registerClass(SubscribeRequest.TYPE,
|
||||
SubscribeRequest.class);
|
||||
TypedObjectFactory.registerClass(UnsubscribeRequest.TYPE,
|
||||
UnsubscribeRequest.class);
|
||||
TypedObjectFactory.registerClass(ForwardEventRequest.TYPE,
|
||||
ForwardEventRequest.class);
|
||||
TypedObjectFactory.registerClass(PingRequest.TYPE,
|
||||
PingRequest.class);
|
||||
TypedObjectFactory.registerClass(LogoffRequest.TYPE,
|
||||
LogoffRequest.class);
|
||||
|
||||
// register our downstream message classes
|
||||
TypedObjectFactory.registerClass(AuthResponse.TYPE,
|
||||
AuthResponse.class);
|
||||
TypedObjectFactory.registerClass(BootstrapNotification.TYPE,
|
||||
BootstrapNotification.class);
|
||||
TypedObjectFactory.registerClass(EventNotification.TYPE,
|
||||
EventNotification.class);
|
||||
TypedObjectFactory.registerClass(ObjectResponse.TYPE,
|
||||
ObjectResponse.class);
|
||||
TypedObjectFactory.registerClass(FailureResponse.TYPE,
|
||||
FailureResponse.class);
|
||||
TypedObjectFactory.registerClass(PongResponse.TYPE,
|
||||
PongResponse.class);
|
||||
|
||||
// register our credential classes
|
||||
TypedObjectFactory.registerClass(UsernamePasswordCreds.TYPE,
|
||||
UsernamePasswordCreds.class);
|
||||
|
||||
// register our event classes
|
||||
TypedObjectFactory.registerClass(AttributeChangedEvent.TYPE,
|
||||
AttributeChangedEvent.class);
|
||||
TypedObjectFactory.registerClass(AttributesChangedEvent.TYPE,
|
||||
AttributesChangedEvent.class);
|
||||
TypedObjectFactory.registerClass(MessageEvent.TYPE,
|
||||
MessageEvent.class);
|
||||
TypedObjectFactory.registerClass(ObjectAddedEvent.TYPE,
|
||||
ObjectAddedEvent.class);
|
||||
TypedObjectFactory.registerClass(ObjectRemovedEvent.TYPE,
|
||||
ObjectRemovedEvent.class);
|
||||
TypedObjectFactory.registerClass(ReleaseLockEvent.TYPE,
|
||||
ReleaseLockEvent.class);
|
||||
TypedObjectFactory.registerClass(ObjectDestroyedEvent.TYPE,
|
||||
ObjectDestroyedEvent.class);
|
||||
TypedObjectFactory.registerClass(EntryAddedEvent.TYPE,
|
||||
EntryAddedEvent.class);
|
||||
TypedObjectFactory.registerClass(EntryRemovedEvent.TYPE,
|
||||
EntryRemovedEvent.class);
|
||||
TypedObjectFactory.registerClass(EntryUpdatedEvent.TYPE,
|
||||
EntryUpdatedEvent.class);
|
||||
TypedObjectFactory.registerClass(ElementUpdatedEvent.TYPE,
|
||||
ElementUpdatedEvent.class);
|
||||
TypedObjectFactory.registerClass(CompoundEvent.TYPE,
|
||||
CompoundEvent.class);
|
||||
}
|
||||
}
|
||||
@@ -1,640 +0,0 @@
|
||||
//
|
||||
// $Id: ValueMarshaller.java,v 1.11 2002/03/20 23:00:11 mdb Exp $
|
||||
|
||||
package com.threerings.presents.io;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.threerings.presents.io.Streamable;
|
||||
import com.threerings.presents.io.StreamableUtil;
|
||||
|
||||
/**
|
||||
* The value marshaller provides a mechanism for marshalling and
|
||||
* unmarshalling values of valid distributed object attribute types
|
||||
* (<code>int</code>, <code>String</code>, etc.). It is used when the type
|
||||
* needs to be accompanied by a type identifier because it cannot be
|
||||
* inferred from the context.
|
||||
*
|
||||
* <p> For example, when we are serializing a distributed object, we don't
|
||||
* use the value marshaller because we can just write the attributes out
|
||||
* in a known order and infer their types on the receiving end. On the
|
||||
* other hand, when serializing an event, we need to use the value
|
||||
* marshaller because we only have an oid, an attribute name and some
|
||||
* arbitrary value at that point. We can't be sure that the oid maps to an
|
||||
* object on the receiving end from which we could determine the type of
|
||||
* that particular attribute.
|
||||
*
|
||||
* <p> Note also that we only deal with distributed object types in object
|
||||
* form (meaning <code>int</code> values have been converted into
|
||||
* <code>Integer</code> instances, etc.).
|
||||
*/
|
||||
public class ValueMarshaller
|
||||
{
|
||||
/**
|
||||
* Writes the supplied value to the output stream preceeded by a type
|
||||
* identifier that will allow us to read it back in on the other end.
|
||||
* The value must be one of the valid distributed object attribute
|
||||
* types.
|
||||
*
|
||||
* @see com.threerings.presents.dobj.DObject
|
||||
* @see #readFrom
|
||||
*/
|
||||
public static void writeTo (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
// if the value is null, we use a special marshaller code to
|
||||
// indicate such
|
||||
if (value == null) {
|
||||
out.writeByte(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// all types except streamable and arrays of streamable have a one
|
||||
// to one mapping from class object to marshaller, but streamables
|
||||
// have to be looked up specially because we are dealing with a
|
||||
// interface implementation of streamable rather than a direct
|
||||
// instance
|
||||
Class vclass = ((value instanceof Streamable) ?
|
||||
Streamable.class :
|
||||
((value instanceof Streamable[]) ?
|
||||
STREAMARRAY_CLASS : value.getClass()));
|
||||
|
||||
Marshaller marsh = (Marshaller)_outmap.get(vclass);
|
||||
if (marsh == null) {
|
||||
throw new RuntimeException("Requested to serialize invalid " +
|
||||
"type [value=" + value + ", type=" +
|
||||
value.getClass().getName() + "].");
|
||||
}
|
||||
|
||||
// write the value out using the appropriate marshaller
|
||||
out.writeByte(marsh.code);
|
||||
marsh.writeValue(out, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a value in from the stream that was previously written out
|
||||
* with <code>writeTo</code>.
|
||||
*
|
||||
* @see #writeTo
|
||||
*/
|
||||
public static Object readFrom (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
byte code = in.readByte();
|
||||
|
||||
// if the value was null, the code will be zero, otherwise it will
|
||||
// reference a valid value marshaller registration
|
||||
if (code == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// look up the marshaller and read in the value
|
||||
Marshaller marsh = (Marshaller)_inmap.get((int)code);
|
||||
if (marsh == null) {
|
||||
throw new RuntimeException("Requested to unserialize invalid " +
|
||||
"type [code=" + code + "].");
|
||||
}
|
||||
return marsh.readValue(in);
|
||||
}
|
||||
|
||||
// test these suckers out
|
||||
public static void main (String[] args)
|
||||
{
|
||||
Object[] values = new Object[15];
|
||||
values[0] = new Boolean(true);
|
||||
values[1] = new Byte((byte)1);
|
||||
values[2] = new Short((short)2);
|
||||
values[3] = new Integer(3);
|
||||
values[4] = new Long(4l);
|
||||
values[5] = new Float(5.0f);
|
||||
values[6] = new Double(6.0);
|
||||
values[7] = "this is a string";
|
||||
values[8] = new byte[] { 0, 1, 2, 3 };
|
||||
values[9] = new short[] { 0, 1, 2, 3 };
|
||||
values[10] = new int[] { 0, 1, 2, 3 };
|
||||
values[11] = new long[] { 0, 1, 2, 3 };
|
||||
values[12] = new float[] { 0.0f, 1.0f, 2.0f, 3.0f };
|
||||
values[13] = new double[] { 0.0, 1.0, 2.0, 3.0 };
|
||||
values[14] = new String[] { "one", "two", "three", "four" };
|
||||
|
||||
File file = new File("test.dat");
|
||||
|
||||
try {
|
||||
FileOutputStream fout = new FileOutputStream(file);
|
||||
BufferedOutputStream bout = new BufferedOutputStream(fout);
|
||||
DataOutputStream dout = new DataOutputStream(bout);
|
||||
|
||||
// write out our values
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
writeTo(dout, values[i]);
|
||||
}
|
||||
|
||||
// close the file
|
||||
dout.flush();
|
||||
fout.close();
|
||||
|
||||
// and read it all back in
|
||||
FileInputStream fin = new FileInputStream(file);
|
||||
BufferedInputStream bin = new BufferedInputStream(fin);
|
||||
DataInputStream din = new DataInputStream(bin);
|
||||
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
Object value = readFrom(din);
|
||||
System.out.println(value.getClass().getName() + ": " + value);
|
||||
}
|
||||
|
||||
fin.close();
|
||||
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
// delete our temp file
|
||||
file.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to marshall and unmarshall values.
|
||||
*/
|
||||
protected static abstract class Marshaller
|
||||
{
|
||||
public byte code;
|
||||
|
||||
public Marshaller (byte code)
|
||||
{
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public abstract void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException;
|
||||
|
||||
public abstract Object readValue (DataInputStream in)
|
||||
throws IOException;
|
||||
}
|
||||
|
||||
protected static class BooleanMarshaller extends Marshaller
|
||||
{
|
||||
public BooleanMarshaller ()
|
||||
{
|
||||
super((byte)1);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeBoolean(((Boolean)value).booleanValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Boolean(in.readBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ByteMarshaller extends Marshaller
|
||||
{
|
||||
public ByteMarshaller ()
|
||||
{
|
||||
super((byte)2);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeByte(((Byte)value).byteValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Byte(in.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ShortMarshaller extends Marshaller
|
||||
{
|
||||
public ShortMarshaller ()
|
||||
{
|
||||
super((byte)3);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeShort(((Short)value).shortValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Short(in.readShort());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class IntegerMarshaller extends Marshaller
|
||||
{
|
||||
public IntegerMarshaller ()
|
||||
{
|
||||
super((byte)4);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeInt(((Integer)value).intValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Integer(in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class LongMarshaller extends Marshaller
|
||||
{
|
||||
public LongMarshaller ()
|
||||
{
|
||||
super((byte)5);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeLong(((Long)value).longValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Long(in.readLong());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class FloatMarshaller extends Marshaller
|
||||
{
|
||||
public FloatMarshaller ()
|
||||
{
|
||||
super((byte)6);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeFloat(((Float)value).floatValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Float(in.readFloat());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class DoubleMarshaller extends Marshaller
|
||||
{
|
||||
public DoubleMarshaller ()
|
||||
{
|
||||
super((byte)7);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeDouble(((Double)value).doubleValue());
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return new Double(in.readDouble());
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StringMarshaller extends Marshaller
|
||||
{
|
||||
public StringMarshaller ()
|
||||
{
|
||||
super((byte)8);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeUTF((String)value);
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return in.readUTF();
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ByteArrayMarshaller extends Marshaller
|
||||
{
|
||||
public ByteArrayMarshaller ()
|
||||
{
|
||||
super((byte)9);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
byte[] data = (byte[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeByte(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
byte[] data = new byte[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readByte();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ShortArrayMarshaller extends Marshaller
|
||||
{
|
||||
public ShortArrayMarshaller ()
|
||||
{
|
||||
super((byte)10);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
short[] data = (short[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeShort(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
short[] data = new short[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readShort();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class IntegerArrayMarshaller extends Marshaller
|
||||
{
|
||||
public IntegerArrayMarshaller ()
|
||||
{
|
||||
super((byte)11);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
int[] data = (int[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeInt(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
int[] data = new int[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readInt();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class LongArrayMarshaller extends Marshaller
|
||||
{
|
||||
public LongArrayMarshaller ()
|
||||
{
|
||||
super((byte)12);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
long[] data = (long[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeLong(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
long[] data = new long[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readLong();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class FloatArrayMarshaller extends Marshaller
|
||||
{
|
||||
public FloatArrayMarshaller ()
|
||||
{
|
||||
super((byte)13);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
float[] data = (float[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeFloat(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
float[] data = new float[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readFloat();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class DoubleArrayMarshaller extends Marshaller
|
||||
{
|
||||
public DoubleArrayMarshaller ()
|
||||
{
|
||||
super((byte)14);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
double[] data = (double[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeDouble(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
double[] data = new double[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readDouble();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StringArrayMarshaller extends Marshaller
|
||||
{
|
||||
public StringArrayMarshaller ()
|
||||
{
|
||||
super((byte)15);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
String[] data = (String[])value;
|
||||
out.writeInt(data.length);
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeUTF((data[i] == null) ? "" : data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
String[] data = new String[in.readInt()];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = in.readUTF();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StreamableMarshaller extends Marshaller
|
||||
{
|
||||
public StreamableMarshaller ()
|
||||
{
|
||||
super((byte)16);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
out.writeUTF(value.getClass().getName());
|
||||
((Streamable)value).writeTo(out);
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
String cname = in.readUTF();
|
||||
try {
|
||||
Streamable value = (Streamable)
|
||||
Class.forName(cname).newInstance();
|
||||
value.readFrom(in);
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Unable to unmarshall streamable " +
|
||||
"[cname=" + cname +
|
||||
", error=" + e + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StreamableArrayMarshaller extends Marshaller
|
||||
{
|
||||
public StreamableArrayMarshaller ()
|
||||
{
|
||||
super((byte)17);
|
||||
}
|
||||
|
||||
public void writeValue (DataOutputStream out, Object value)
|
||||
throws IOException
|
||||
{
|
||||
StreamableUtil.writeStreamables(out, (Streamable[])value);
|
||||
}
|
||||
|
||||
public Object readValue (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
return StreamableUtil.readStreamables(in);
|
||||
}
|
||||
}
|
||||
|
||||
protected static HashMap _outmap = new HashMap();
|
||||
protected static HashIntMap _inmap = new HashIntMap();
|
||||
|
||||
protected static final Class STREAMARRAY_CLASS =
|
||||
(new Streamable[0]).getClass();
|
||||
|
||||
protected static Class[] _classes = {
|
||||
Boolean.class,
|
||||
Byte.class,
|
||||
Short.class,
|
||||
Integer.class,
|
||||
Long.class,
|
||||
Float.class,
|
||||
Double.class,
|
||||
String.class,
|
||||
Streamable.class,
|
||||
(new byte[0]).getClass(),
|
||||
(new short[0]).getClass(),
|
||||
(new int[0]).getClass(),
|
||||
(new long[0]).getClass(),
|
||||
(new float[0]).getClass(),
|
||||
(new double[0]).getClass(),
|
||||
(new String[0]).getClass(),
|
||||
STREAMARRAY_CLASS,
|
||||
};
|
||||
|
||||
protected static Marshaller[] _marshallers = {
|
||||
new BooleanMarshaller(),
|
||||
new ByteMarshaller(),
|
||||
new ShortMarshaller(),
|
||||
new IntegerMarshaller(),
|
||||
new LongMarshaller(),
|
||||
new FloatMarshaller(),
|
||||
new DoubleMarshaller(),
|
||||
new StringMarshaller(),
|
||||
new StreamableMarshaller(),
|
||||
new ByteArrayMarshaller(),
|
||||
new ShortArrayMarshaller(),
|
||||
new IntegerArrayMarshaller(),
|
||||
new LongArrayMarshaller(),
|
||||
new FloatArrayMarshaller(),
|
||||
new DoubleArrayMarshaller(),
|
||||
new StringArrayMarshaller(),
|
||||
new StreamableArrayMarshaller(),
|
||||
};
|
||||
|
||||
// register our marshallers
|
||||
static {
|
||||
Marshaller marsh;
|
||||
for (int i = 0; i < _classes.length; i++) {
|
||||
marsh = _marshallers[i];
|
||||
_outmap.put(_classes[i], marsh);
|
||||
_inmap.put(marsh.code, marsh);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user