From 6717f8d6e5ac699f2bbbdb227c32951672a8cd92 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 23 May 2001 04:03:41 +0000 Subject: [PATCH] More code, more code, more kibbles and code. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/presents/client/Client.java | 6 +- .../presents/client/Communicator.java | 287 ++++++++++++++++-- .../com/threerings/presents/dobj/DObject.java | 4 +- .../threerings/presents/io/TypedObject.java | 26 +- .../presents/io/TypedObjectFactory.java | 15 +- .../threerings/presents/net/AuthRequest.java | 4 +- .../threerings/presents/net/AuthResponse.java | 19 +- .../presents/net/AuthResponseData.java | 21 ++ .../threerings/presents/net/Credentials.java | 30 +- .../presents/net/DownstreamMessage.java | 30 +- .../presents/net/ObjectResponse.java | 4 +- .../presents/net/UpstreamMessage.java | 6 +- .../presents/net/UsernamePasswordCreds.java | 4 +- .../threerings/presents/util/CherCodes.java | 17 ++ 14 files changed, 402 insertions(+), 71 deletions(-) create mode 100644 src/java/com/threerings/presents/net/AuthResponseData.java create mode 100644 src/java/com/threerings/presents/util/CherCodes.java 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"; +}