diff --git a/src/java/com/threerings/presents/client/Client.java b/src/java/com/threerings/presents/client/Client.java
index 013c0f395..cc5d7f8af 100644
--- a/src/java/com/threerings/presents/client/Client.java
+++ b/src/java/com/threerings/presents/client/Client.java
@@ -1,5 +1,5 @@
//
-// $Id: Client.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
+// $Id: Client.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.client;
@@ -152,7 +152,7 @@ public class Client
case CLIENT_FAILED_TO_LOGON:
obs.clientFailedToLogon(this, cause);
break;
- case CLIENT_CONNETION_FAILED:
+ case CLIENT_CONNECTION_FAILED:
obs.clientConnectionFailed(this, cause);
break;
case CLIENT_WILL_LOGOFF:
@@ -191,7 +191,7 @@ public class Client
// client observer codes
static final int CLIENT_DID_LOGON = 0;
static final int CLIENT_FAILED_TO_LOGON = 1;
- static final int CLIENT_CONNETION_FAILED = 2;
+ static final int CLIENT_CONNECTION_FAILED = 2;
static final int CLIENT_WILL_LOGOFF = 3;
static final int CLIENT_DID_LOGOFF = 4;
}
diff --git a/src/java/com/threerings/presents/client/Communicator.java b/src/java/com/threerings/presents/client/Communicator.java
index d87f01fc1..cd737ef95 100644
--- a/src/java/com/threerings/presents/client/Communicator.java
+++ b/src/java/com/threerings/presents/client/Communicator.java
@@ -1,5 +1,5 @@
//
-// $Id: Communicator.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: Communicator.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.client;
@@ -10,8 +10,10 @@ import java.net.InetAddress;
import com.samskivert.util.Queue;
import com.samskivert.cocktail.cher.Log;
-import com.samskivert.cocktail.cher.io.FramingOutputStream;
+import com.samskivert.cocktail.cher.io.*;
+import com.samskivert.cocktail.cher.io.ObjectStreamException;
import com.samskivert.cocktail.cher.net.*;
+import com.samskivert.cocktail.cher.util.Codes;
/**
* The client performs all network I/O on separate threads (one for
@@ -69,12 +71,59 @@ class Communicator
* network connection. Also causes all communication threads to
* terminate.
*/
- public void logoff ()
+ public synchronized void logoff ()
{
+ // if our socket is already closed, we've already taken care of
+ // this business
+ if (_socket == null) {
+ return;
+ }
+
+ // let our reader and writer know that it's time to go
+ if (_reader != null) {
+ // if logoff() is being called by the client as part of a
+ // normal shutdown, this will cause the reader thread to be
+ // interrupted and shutdown gracefully. if logoff is being
+ // called by the reader thread as a result of a failed socket,
+ // it won't interrupt itself as it is already shutting down
+ // gracefully. if the JVM is buggy and calling interrupt() on
+ // a thread that is blocked on a socket doesn't wake it up,
+ // then when we close() the socket a bit further down, we have
+ // another chance that the reader thread will wake up; this
+ // time slightly less gracefully because it will think there's
+ // a network error when in fact we're just shutting down, but
+ // at least it will cleanly exit
+ _reader.shutdown();
+ }
+ if (_writer != null) {
+ // shutting down the writer thread is simpler because we can
+ // post a termination message on the queue and be sure that it
+ // will receive it. we do run the risk that it is in the
+ // middle of trying to send a message when we close the
+ // socket, but in theory the send will fail, it will complain
+ // and then it will cleanly exit. if we were uber paranoid
+ // about JVMs misbehaving on simultaneous close()/write(), we
+ // could wait here for the writer thread to exit, but that
+ // makes me even more nervous because I know that some JVMs
+ // don't handle Thread.join() properly (hopefully no one is
+ // still using those JVMs but one can never be sure)
+ _writer.shutdown();
+ }
+
+ // close down our socket
+ try {
+ _socket.close();
+ } catch (IOException cle) {
+ Log.warning("Error closing failed socket: " + cle);
+ }
+ _socket = null;
+
+ // let the client observers know that we're logged off
+ _client.notifyObservers(Client.CLIENT_DID_LOGOFF, null);
}
/**
- * Queues up the specified message for delivery to the server.
+ * Queues up the specified message for delivery upstream.
*/
public void postMessage (UpstreamMessage msg)
{
@@ -82,17 +131,46 @@ class Communicator
_msgq.append(msg);
}
- protected void startWriter ()
+ /**
+ * Callback called by the reader when the authentication process
+ * completes successfully. Here we extract the bootstrap information
+ * for the client and start up the writer thread to manage the other
+ * half of our bi-directional message stream.
+ */
+ protected synchronized void logonSucceeded (AuthResponseData data)
{
+ // extract bootstrap information
+
+ // create a new writer thread and start it up
if (_writer != null) {
throw new RuntimeException("Writer already started!?");
}
-
- // create a new writer thread and start it up
_writer = new Writer();
_writer.start();
}
+ /**
+ * Callback called by the reader or writer thread when something goes
+ * awry with our socket connection to the server.
+ */
+ protected synchronized void connectionFailed (IOException ioe)
+ {
+ // make sure the socket isn't already closed down (meaning we've
+ // already dealt with the failed connection)
+ if (_socket == null) {
+ return;
+ }
+
+ // let the client know that things went south
+ _client.notifyObservers(Client.CLIENT_CONNECTION_FAILED, ioe);
+
+ // and request that we go through the motions of logging off
+ logoff();
+ }
+
+ /**
+ * Callback called by the reader thread when it goes away.
+ */
protected synchronized void readerDidExit ()
{
// clear out our reader reference
@@ -100,6 +178,19 @@ class Communicator
// let the client know when we finally go away
_client.communicatorDidExit();
+
+ Log.info("Reader thread exited.");
+ }
+
+ /**
+ * Callback called by the writer thread when it goes away.
+ */
+ protected synchronized void writerDidExit ()
+ {
+ // clear out our writer reference
+ _writer = null;
+
+ Log.info("Writer thread exited.");
}
/**
@@ -109,7 +200,7 @@ class Communicator
throws IOException
{
// first we flatten the message so that we can measure it's length
- msg.writeTo(_dout);
+ TypedObjectFactory.writeTo(_dout, msg);
// then write the framed message to actual output stream
_fout.writeFrameAndReset(_out);
}
@@ -121,11 +212,19 @@ class Communicator
protected DownstreamMessage receiveMessage ()
throws IOException
{
- // read the frame size which comes first
- int count = _din.readInt();
+ // read in the next message frame
+ _fin.clearAndReadFrame(_in);
+ // then use the typed object factory to read and decode the proper
+ // downstream message instance
+ return (DownstreamMessage)TypedObjectFactory.readFrom(_din);
+ }
- // now read
- return null;
+ /**
+ * Callback called by the reader thread when it has parsed a new
+ * message from the socket and wishes to have it processed.
+ */
+ protected void processMessage (DownstreamMessage msg)
+ {
}
/**
@@ -154,10 +253,9 @@ class Communicator
return;
}
- // once authenticated, we go into full-duplex mode,
- // starting up another thread to listen for messages while
- // we handle the delivery of messages
- startWriter();
+ // now that we're authenticated, we manage the reading
+ // half of things by continuously reading messages from
+ // the socket and processing them
listen();
} finally {
@@ -166,6 +264,22 @@ class Communicator
}
}
+ /**
+ * Informs the reader thread that it's no longer running. The next
+ * time through the read loop, it will exit.
+ */
+ public synchronized void shutdown ()
+ {
+ _running = false;
+
+ // if we are not the reader thread, then we want to interrupt
+ // the reader thread as it may be blocked listening to the
+ // socket
+ if (Thread.currentThread() != this) {
+ interrupt();
+ }
+ }
+
protected void connect ()
throws IOException
{
@@ -180,13 +294,14 @@ class Communicator
// establish a socket connection to said server
_socket = new Socket(host, _client.getPort());
- // create our input and output streams
- InputStream in = _socket.getInputStream();
- _din = new DataInputStream(new BufferedInputStream(in));
+ // get a handle on our input and output streams
+ _in = _socket.getInputStream();
_out = _socket.getOutputStream();
- // we frame our messages here and then write them directly to
- // the real output stream
+ // our messages are framed (preceded by their length), so we
+ // use these helper streams to manage the framing
+ _fin = new FramedInputStream();
+ _din = new DataInputStream(_fin);
_fout = new FramingOutputStream();
_dout = new DataOutputStream(_fout);
}
@@ -197,11 +312,74 @@ class Communicator
// construct an auth request and send it
AuthRequest req = new AuthRequest(_client.getCredentials());
sendMessage(req);
+
+ // now wait for the auth response
+ AuthResponse rsp = (AuthResponse)receiveMessage();
+ AuthResponseData data = rsp.getData();
+
+ // if the auth request failed, we want to let the communicator
+ // know by throwing a login exception
+ if (!data.code.equals(Codes.SUCCESS)) {
+ throw new LogonException(data.code);
+ }
+
+ // we're all clear. let the communicator know that we're in
+ logonSucceeded(data);
}
protected void listen ()
{
+ DownstreamMessage msg = null;
+
+ while (isRunning()) {
+ try {
+ // read the next message from the socket
+ msg = receiveMessage();
+
+ // process the message
+ processMessage(msg);
+
+ } catch (ObjectStreamException ose) {
+ Log.warning("Error decoding message: " + ose);
+ // move on to the next message
+
+ } catch (InterruptedIOException iioe) {
+ // somebody set up us the bomb! we've been interrupted
+ // which means that we're being shut down, so we
+ // simply fall through and isRunning() will return
+ // false next time through the loop
+ Log.info("Reader thread woken up in time to die.");
+
+ } catch (EOFException eofe) {
+ Log.info("Connection closed by peer.");
+ // nothing left for us to do
+ shutdown();
+
+ } catch (IOException ioe) {
+ // let the communicator know that our connection
+ // failed
+ connectionFailed(ioe);
+ // and shut ourselves down
+ shutdown();
+
+ } catch (Exception e) {
+ Log.warning("Error processing message [msg=" + msg +
+ ", error=" + e + "].");
+ // move on to the next message
+ }
+ }
}
+
+ /**
+ * Must access _running via this member function to ensure that we
+ * are Chapter 17 compliant.
+ */
+ protected synchronized boolean isRunning ()
+ {
+ return _running;
+ }
+
+ protected boolean _running = true;
}
/**
@@ -213,6 +391,67 @@ class Communicator
{
public void run ()
{
+ try {
+ while (isRunning()) {
+ // fetch the next message from the queue
+ UpstreamMessage msg = (UpstreamMessage)_msgq.get();
+
+ // if this is a termination message, we're being
+ // requested to exit, so we want to bail now rather
+ // than continuing
+ if (msg instanceof TerminationMessage) {
+ break;
+ }
+
+ try {
+ // write the message out the socket
+ sendMessage(msg);
+
+ } catch (IOException ioe) {
+ // let the communicator know if we have any
+ // problems
+ connectionFailed(ioe);
+ // and bail
+ shutdown();
+ }
+ }
+
+ } finally {
+ writerDidExit();
+ }
+ }
+
+ /**
+ * Informs the writer thread that it's no longer running. The next
+ * time through the write loop, it will exit.
+ */
+ public synchronized void shutdown ()
+ {
+ _running = false;
+
+ // post a bogus message to the outgoing queue to ensure that
+ // the writer thread notices that it's time to go
+ postMessage(new TerminationMessage());
+ }
+
+ /**
+ * Must access _running via this member function to ensure that we
+ * are Chapter 17 compliant.
+ */
+ protected synchronized boolean isRunning ()
+ {
+ return _running;
+ }
+
+ protected boolean _running = true;
+ }
+
+ /** This is used to terminate the writer thread. */
+ protected static class TerminationMessage extends UpstreamMessage
+ {
+ public short getType ()
+ {
+ return -1;
}
}
@@ -221,11 +460,15 @@ class Communicator
protected Writer _writer;
protected Socket _socket;
- protected DataInputStream _din;
+ protected InputStream _in;
protected OutputStream _out;
protected Queue _msgq = new Queue();
/** We use this to frame our upstream messages. */
protected FramingOutputStream _fout;
protected DataOutputStream _dout;
+
+ /** We use this to frame our downstream messages. */
+ protected FramedInputStream _fin;
+ protected DataInputStream _din;
}
diff --git a/src/java/com/threerings/presents/dobj/DObject.java b/src/java/com/threerings/presents/dobj/DObject.java
index a53897501..798792e87 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.1 2001/05/22 21:51:29 mdb Exp $
+// $Id: DObject.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.dobj;
@@ -10,7 +10,7 @@ import java.io.DataOutputStream;
import com.samskivert.cocktail.cher.io.TypedObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
-public class DObject extends TypedObject
+public class DObject implements TypedObject
{
public static short TYPE = 400;
diff --git a/src/java/com/threerings/presents/io/TypedObject.java b/src/java/com/threerings/presents/io/TypedObject.java
index da873c6d4..b99abfb0d 100644
--- a/src/java/com/threerings/presents/io/TypedObject.java
+++ b/src/java/com/threerings/presents/io/TypedObject.java
@@ -1,5 +1,5 @@
//
-// $Id: TypedObject.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
+// $Id: TypedObject.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.io;
@@ -10,9 +10,12 @@ import java.io.DataOutputStream;
/**
* 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.
+ * end to instantiate the proper typed object class for decoding (which is
+ * done by the TypedObjectFactory).
+ *
+ * @see TypedObjectFactory
*/
-public abstract class TypedObject
+public interface TypedObject
{
/**
* Each typed object class must associate itself with a type value via
@@ -22,28 +25,17 @@ public abstract class TypedObject
*
* @return The type code associated with this object.
*/
- public abstract short getType ();
+ public short getType ();
/**
* Each typed object class must be able to write itself to a stream.
- * It should first call super.writeTo() before writing
- * its own fields to the stream.
*/
public void writeTo (DataOutputStream out)
- throws IOException
- {
- out.writeShort(getType());
- }
+ throws IOException;
/**
* Each typed object class must be able to read itself from a stream.
- * It should first call super.readFrom() before reading
- * its own fields from the stream.
*/
public void readFrom (DataInputStream in)
- throws IOException
- {
- // nothing to do because the TypedObjectFactory already read our
- // type value from the stream
- }
+ throws IOException;
}
diff --git a/src/java/com/threerings/presents/io/TypedObjectFactory.java b/src/java/com/threerings/presents/io/TypedObjectFactory.java
index 0c1e4d278..d6829a06e 100644
--- a/src/java/com/threerings/presents/io/TypedObjectFactory.java
+++ b/src/java/com/threerings/presents/io/TypedObjectFactory.java
@@ -1,5 +1,5 @@
//
-// $Id: TypedObjectFactory.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: TypedObjectFactory.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.io;
@@ -37,6 +37,19 @@ public class TypedObjectFactory
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
diff --git a/src/java/com/threerings/presents/net/AuthRequest.java b/src/java/com/threerings/presents/net/AuthRequest.java
index 5f201beb8..3f039bded 100644
--- a/src/java/com/threerings/presents/net/AuthRequest.java
+++ b/src/java/com/threerings/presents/net/AuthRequest.java
@@ -1,5 +1,5 @@
//
-// $Id: AuthRequest.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: AuthRequest.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -39,7 +39,7 @@ public class AuthRequest extends UpstreamMessage
throws IOException
{
super.writeTo(out);
- _creds.writeTo(out);
+ TypedObjectFactory.writeTo(out, _creds);
}
public void readFrom (DataInputStream in)
diff --git a/src/java/com/threerings/presents/net/AuthResponse.java b/src/java/com/threerings/presents/net/AuthResponse.java
index 174299a8f..e29fb0031 100644
--- a/src/java/com/threerings/presents/net/AuthResponse.java
+++ b/src/java/com/threerings/presents/net/AuthResponse.java
@@ -1,5 +1,5 @@
//
-// $Id: AuthResponse.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
+// $Id: AuthResponse.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -7,7 +7,6 @@ import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
-import com.samskivert.cocktail.cher.dobj.DObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
/**
@@ -22,12 +21,6 @@ public class AuthResponse extends DownstreamMessage
/** The code for an auth response. */
public static final short TYPE = TYPE_BASE + 0;
- /** The response code key in the data object. */
- public static final String CODE = "code";
-
- /** The failure reason key in the data object. */
- public static final String REASON = "reason";
-
/**
* Zero argument constructor used when unserializing an instance.
*/
@@ -39,12 +32,12 @@ public class AuthResponse extends DownstreamMessage
/**
* Constructs a auth response with the supplied credentials.
*/
- public AuthResponse (DObject data)
+ public AuthResponse (AuthResponseData data)
{
_data = data;
}
- public DObject getData ()
+ public AuthResponseData getData ()
{
return _data;
}
@@ -58,15 +51,15 @@ public class AuthResponse extends DownstreamMessage
throws IOException
{
super.writeTo(out);
- _data.writeTo(out);
+ TypedObjectFactory.writeTo(out, _data);
}
public void readFrom (DataInputStream in)
throws IOException
{
super.readFrom(in);
- _data = (DObject)TypedObjectFactory.readFrom(in);
+ _data = (AuthResponseData)TypedObjectFactory.readFrom(in);
}
- protected DObject _data;
+ protected AuthResponseData _data;
}
diff --git a/src/java/com/threerings/presents/net/AuthResponseData.java b/src/java/com/threerings/presents/net/AuthResponseData.java
new file mode 100644
index 000000000..48363d0b3
--- /dev/null
+++ b/src/java/com/threerings/presents/net/AuthResponseData.java
@@ -0,0 +1,21 @@
+//
+// $Id: AuthResponseData.java,v 1.1 2001/05/23 04:03:40 mdb Exp $
+
+package com.samskivert.cocktail.cher.net;
+
+import com.samskivert.cocktail.cher.dobj.DObject;
+
+/**
+ * An AuthResponseData object is communicated back to the
+ * client along with an authentication response. It contains an indicator
+ * of authentication success or failure along with bootstrap information
+ * for the client.
+ */
+public class AuthResponseData extends DObject
+{
+ /**
+ * Either the string "success" or a reason code for why authentication
+ * failed.
+ */
+ public String code;
+}
diff --git a/src/java/com/threerings/presents/net/Credentials.java b/src/java/com/threerings/presents/net/Credentials.java
index 3dfc6d3fc..d6499f43a 100644
--- a/src/java/com/threerings/presents/net/Credentials.java
+++ b/src/java/com/threerings/presents/net/Credentials.java
@@ -1,8 +1,12 @@
//
-// $Id: Credentials.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
+// $Id: Credentials.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
import com.samskivert.cocktail.cher.io.TypedObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
@@ -17,7 +21,7 @@ import com.samskivert.cocktail.cher.io.TypedObjectFactory;
* that they can be instantiated prior to reconstruction from a data input
* stream.
*/
-public abstract class Credentials extends TypedObject
+public abstract class Credentials implements TypedObject
{
/**
* All credential derived classes should base their typed object code
@@ -25,6 +29,28 @@ public abstract class Credentials extends TypedObject
*/
public static final short TYPE_BASE = 300;
+ /**
+ * Derived classes should override this function to write their fields
+ * out to the supplied data output stream. They must be sure
+ * to first call super.writeTo().
+ */
+ public void writeTo (DataOutputStream out)
+ throws IOException
+ {
+ // we don't do anything here, but we may want to some day
+ }
+
+ /**
+ * Derived classes should override this function to read their fields
+ * from the supplied data input stream. They must be sure to
+ * first call super.readFrom().
+ */
+ public void readFrom (DataInputStream in)
+ throws IOException
+ {
+ // we don't do anything here, but we may want to some day
+ }
+
// register our credential classes
static {
TypedObjectFactory.registerClass(UsernamePasswordCreds.TYPE,
diff --git a/src/java/com/threerings/presents/net/DownstreamMessage.java b/src/java/com/threerings/presents/net/DownstreamMessage.java
index 035e33a6d..bd74d6a06 100644
--- a/src/java/com/threerings/presents/net/DownstreamMessage.java
+++ b/src/java/com/threerings/presents/net/DownstreamMessage.java
@@ -1,8 +1,12 @@
//
-// $Id: DownstreamMessage.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: DownstreamMessage.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
+import java.io.IOException;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+
import com.samskivert.cocktail.cher.io.TypedObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
@@ -12,7 +16,7 @@ import com.samskivert.cocktail.cher.io.TypedObjectFactory;
* client. Downstream messages include object subscription, event
* forwarding and session management.
*/
-public abstract class DownstreamMessage extends TypedObject
+public abstract class DownstreamMessage implements TypedObject
{
/**
* All downstream message derived classes should base their typed
@@ -41,6 +45,28 @@ public abstract class DownstreamMessage extends TypedObject
// nothing to do...
}
+ /**
+ * Derived classes should override this function to write their fields
+ * out to the supplied data output stream. They must be sure
+ * to first call super.writeTo().
+ */
+ public void writeTo (DataOutputStream out)
+ throws IOException
+ {
+ // we don't do anything here, but we may want to some day
+ }
+
+ /**
+ * Derived classes should override this function to read their fields
+ * from the supplied data input stream. They must be sure to
+ * first call super.readFrom().
+ */
+ public void readFrom (DataInputStream in)
+ throws IOException
+ {
+ // we don't do anything here, but we may want to some day
+ }
+
// register our downstream message classes
static {
TypedObjectFactory.registerClass(AuthResponse.TYPE,
diff --git a/src/java/com/threerings/presents/net/ObjectResponse.java b/src/java/com/threerings/presents/net/ObjectResponse.java
index 7080657ea..9d4d89682 100644
--- a/src/java/com/threerings/presents/net/ObjectResponse.java
+++ b/src/java/com/threerings/presents/net/ObjectResponse.java
@@ -1,5 +1,5 @@
//
-// $Id: ObjectResponse.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
+// $Id: ObjectResponse.java,v 1.2 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -43,7 +43,7 @@ public class ObjectResponse extends DownstreamMessage
{
super.writeTo(out);
out.writeShort(messageId);
- _dobj.writeTo(out);
+ TypedObjectFactory.writeTo(out, _dobj);
}
public void readFrom (DataInputStream in)
diff --git a/src/java/com/threerings/presents/net/UpstreamMessage.java b/src/java/com/threerings/presents/net/UpstreamMessage.java
index 37424d53d..4279c85d9 100644
--- a/src/java/com/threerings/presents/net/UpstreamMessage.java
+++ b/src/java/com/threerings/presents/net/UpstreamMessage.java
@@ -1,5 +1,5 @@
//
-// $Id: UpstreamMessage.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: UpstreamMessage.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -16,7 +16,7 @@ import com.samskivert.cocktail.cher.io.TypedObjectFactory;
* Upstream messages include object subscription, event forwarding and
* session management.
*/
-public abstract class UpstreamMessage extends TypedObject
+public abstract class UpstreamMessage implements TypedObject
{
/**
* All upstream message derived classes should base their typed object
@@ -53,7 +53,6 @@ public abstract class UpstreamMessage extends TypedObject
public void writeTo (DataOutputStream out)
throws IOException
{
- super.writeTo(out);
out.writeShort(messageId);
}
@@ -65,7 +64,6 @@ public abstract class UpstreamMessage extends TypedObject
public void readFrom (DataInputStream in)
throws IOException
{
- super.readFrom(in);
messageId = in.readShort();
}
diff --git a/src/java/com/threerings/presents/net/UsernamePasswordCreds.java b/src/java/com/threerings/presents/net/UsernamePasswordCreds.java
index a7f93dc8b..be2a37519 100644
--- a/src/java/com/threerings/presents/net/UsernamePasswordCreds.java
+++ b/src/java/com/threerings/presents/net/UsernamePasswordCreds.java
@@ -1,5 +1,5 @@
//
-// $Id: UsernamePasswordCreds.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
+// $Id: UsernamePasswordCreds.java,v 1.3 2001/05/23 04:03:40 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -36,6 +36,7 @@ public class UsernamePasswordCreds extends Credentials
public void writeTo (DataOutputStream out)
throws IOException
{
+ super.writeTo(out);
out.writeUTF(_username);
out.writeUTF(_password);
}
@@ -43,6 +44,7 @@ public class UsernamePasswordCreds extends Credentials
public void readFrom (DataInputStream in)
throws IOException
{
+ super.readFrom(in);
_username = in.readUTF();
_password = in.readUTF();
}
diff --git a/src/java/com/threerings/presents/util/CherCodes.java b/src/java/com/threerings/presents/util/CherCodes.java
new file mode 100644
index 000000000..3d34a6c4c
--- /dev/null
+++ b/src/java/com/threerings/presents/util/CherCodes.java
@@ -0,0 +1,17 @@
+//
+// $Id: CherCodes.java,v 1.1 2001/05/23 04:03:41 mdb Exp $
+
+package com.samskivert.cocktail.cher.util;
+
+/**
+ * The Codes class serves as a repository for miscellaneous
+ * string and integer constants used by componenets of the Cher system.
+ */
+public class Codes
+{
+ /**
+ * Generally used in responses that can either have the value success,
+ * or a string code explaining the reason for failure.
+ */
+ public static final String SUCCESS = "success";
+}