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:
Michael Bayne
2002-07-23 05:41:59 +00:00
parent ffb030d40a
commit 2601ab2321
29 changed files with 0 additions and 2545 deletions
@@ -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);
}
}
}