diff --git a/src/java/com/threerings/presents/dobj/AttributeChangedEvent.java b/src/java/com/threerings/presents/dobj/AttributeChangedEvent.java index 60d3ef9b0..2c8b00eec 100644 --- a/src/java/com/threerings/presents/dobj/AttributeChangedEvent.java +++ b/src/java/com/threerings/presents/dobj/AttributeChangedEvent.java @@ -1,5 +1,5 @@ // -// $Id: AttributeChangedEvent.java,v 1.4 2001/06/11 17:44:04 mdb Exp $ +// $Id: AttributeChangedEvent.java,v 1.5 2001/06/12 02:57:30 mdb Exp $ package com.threerings.cocktail.cher.dobj; @@ -8,7 +8,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.lang.reflect.Method; -import com.threerings.cocktail.cher.Log; +import com.threerings.cocktail.cher.dobj.io.ValueMarshaller; /** * An attribute changed event is dispatched when a single attribute of a @@ -123,7 +123,7 @@ public class AttributeChangedEvent extends TypedEvent { super.writeTo(out); out.writeUTF(_name); - // out.write...(_value); + ValueMarshaller.writeTo(out, _value); } public void readFrom (DataInputStream in) @@ -131,7 +131,7 @@ public class AttributeChangedEvent extends TypedEvent { super.readFrom(in); _name = in.readUTF(); - // _value = in.read... + _value = ValueMarshaller.readFrom(in); } public String toString () diff --git a/src/java/com/threerings/presents/dobj/AttributesChangedEvent.java b/src/java/com/threerings/presents/dobj/AttributesChangedEvent.java index 8c359c89a..d86928dd4 100644 --- a/src/java/com/threerings/presents/dobj/AttributesChangedEvent.java +++ b/src/java/com/threerings/presents/dobj/AttributesChangedEvent.java @@ -1,5 +1,5 @@ // -// $Id: AttributesChangedEvent.java,v 1.3 2001/06/11 17:44:04 mdb Exp $ +// $Id: AttributesChangedEvent.java,v 1.4 2001/06/12 02:57:30 mdb Exp $ package com.threerings.cocktail.cher.dobj; @@ -7,6 +7,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import com.threerings.cocktail.cher.dobj.io.ValueMarshaller; + /** * An attributes changed event is dispatched when multiple * attributes of a distributed object have been changed in a single @@ -171,7 +173,7 @@ public class AttributesChangedEvent extends TypedEvent out.writeInt(_count); for (int i = 0; i < _count; i++) { out.writeUTF(_names[i]); - // out.write...(_values[i]); + ValueMarshaller.writeTo(out, _values[i]); } } @@ -184,7 +186,7 @@ public class AttributesChangedEvent extends TypedEvent _values = new Object[_count]; for (int i = 0; i < _count; i++) { _names[i] = in.readUTF(); - // _values[i] = ... + _values[i] = ValueMarshaller.readFrom(in); } } diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java index 4fb8e1b76..11d3a37ac 100644 --- a/src/java/com/threerings/presents/dobj/DObject.java +++ b/src/java/com/threerings/presents/dobj/DObject.java @@ -1,5 +1,5 @@ // -// $Id: DObject.java,v 1.9 2001/06/09 23:39:04 mdb Exp $ +// $Id: DObject.java,v 1.10 2001/06/12 02:57:30 mdb Exp $ package com.threerings.cocktail.cher.dobj; @@ -70,6 +70,15 @@ import java.util.ArrayList; * * These method calls on the actual distributed object will result in the * proper attribute change events being generated and dispatched. + * + *

Note that distributed object fields can only be of a limited set of + * supported types. These types are: + * + *

+ * byte, short, int, long, float, double
+ * Byte, Short, Integer, Long, Float, Double, String
+ * byte[], short[], int[], long[], float[], double[], String[]
+ * 
*/ public class DObject { diff --git a/src/java/com/threerings/presents/io/ValueMarshaller.java b/src/java/com/threerings/presents/io/ValueMarshaller.java new file mode 100644 index 000000000..6d441d3be --- /dev/null +++ b/src/java/com/threerings/presents/io/ValueMarshaller.java @@ -0,0 +1,531 @@ +// +// $Id: ValueMarshaller.java,v 1.1 2001/06/12 02:57:30 mdb Exp $ + +package com.threerings.cocktail.cher.dobj.io; + +import java.io.*; +import java.util.HashMap; + +import com.samskivert.util.IntMap; + +/** + * The value marshaller provides a mechanism for marshalling and + * unmarshalling values of valid distributed object attribute types + * (int, String, etc.). It is used when the type + * needs to be accompanied by a type identifier because it cannot be + * inferred from the context. + * + *

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. + * + *

Note also that we only deal with distributed object types in object + * form (meaning int values have been converted into + * Integer 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 DObject + * @see #readFrom + */ + public static void writeTo (DataOutputStream out, Object value) + throws IOException + { + Marshaller marsh = (Marshaller)_outmap.get(value.getClass()); + 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 writeTo. + * + * @see #writeTo + */ + public static Object readFrom (DataInputStream in) + throws IOException + { + byte code = in.readByte(); + 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[14]; + values[0] = new Byte((byte)1); + values[1] = new Short((short)2); + values[2] = new Integer(3); + values[3] = new Long(4l); + values[4] = new Float(5.0f); + values[5] = new Double(6.0); + values[6] = "this is a string"; + values[7] = new byte[] { 0, 1, 2, 3 }; + values[8] = new short[] { 0, 1, 2, 3 }; + values[9] = new int[] { 0, 1, 2, 3 }; + values[10] = new long[] { 0, 1, 2, 3 }; + values[11] = new float[] { 0.0f, 1.0f, 2.0f, 3.0f }; + values[12] = new double[] { 0.0, 1.0, 2.0, 3.0 }; + values[13] = 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 ByteMarshaller extends Marshaller + { + public ByteMarshaller () + { + super((byte)1); + } + + 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)2); + } + + 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)3); + } + + 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)4); + } + + 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)5); + } + + 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)6); + } + + 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)7); + } + + 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)8); + } + + 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)9); + } + + 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)10); + } + + 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)11); + } + + 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)12); + } + + 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)13); + } + + 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)14); + } + + 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]); + } + } + + 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 HashMap _outmap = new HashMap(); + protected static IntMap _inmap = new IntMap(); + + protected static Class[] _classes = { + Byte.class, + Short.class, + Integer.class, + Long.class, + Float.class, + Double.class, + String.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() + }; + + protected static Marshaller[] _marshallers = { + new ByteMarshaller(), + new ShortMarshaller(), + new IntegerMarshaller(), + new LongMarshaller(), + new FloatMarshaller(), + new DoubleMarshaller(), + new StringMarshaller(), + new ByteArrayMarshaller(), + new ShortArrayMarshaller(), + new IntegerArrayMarshaller(), + new LongArrayMarshaller(), + new FloatArrayMarshaller(), + new DoubleArrayMarshaller(), + new StringArrayMarshaller() + }; + + // 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); + } + } +}