Further progress. Heeya!

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-05-22 21:51:29 +00:00
parent 40ecd80e09
commit f8f3645f67
16 changed files with 801 additions and 64 deletions
@@ -1,5 +1,5 @@
//
// $Id: Communicator.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: Communicator.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.client;
@@ -8,7 +8,9 @@ import java.net.Socket;
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.net.*;
/**
@@ -100,6 +102,38 @@ class Communicator
_client.communicatorDidExit();
}
/**
* Writes the supplied message to the socket.
*/
protected void sendMessage (UpstreamMessage msg)
throws IOException
{
// first we flatten the message so that we can measure it's length
msg.writeTo(_dout);
// then write the framed message to actual output stream
_fout.writeFrameAndReset(_out);
}
/**
* Reads a new message from the socket (blocking until a message has
* arrived).
*/
protected DownstreamMessage receiveMessage ()
throws IOException
{
// read the frame size which comes first
int count = _din.readInt();
// now read
return null;
}
/**
* The reader encapsulates the authentication and message reading
* process. It calls back to the <code>Communicator</code> class to do
* things, but the general flow of the reader thread is encapsulated
* in this class.
*/
protected class Reader extends Thread
{
public void run ()
@@ -145,11 +179,24 @@ 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));
_out = _socket.getOutputStream();
// we frame our messages here and then write them directly to
// the real output stream
_fout = new FramingOutputStream();
_dout = new DataOutputStream(_fout);
}
protected void logon ()
throws LogonException
throws IOException, LogonException
{
// construct an auth request and send it
AuthRequest req = new AuthRequest(_client.getCredentials());
sendMessage(req);
}
protected void listen ()
@@ -157,6 +204,11 @@ class Communicator
}
}
/**
* The writer encapsulates the message writing process. It calls back
* to the <code>Communicator</code> class to do things, but the
* general flow of the writer thread is encapsulated in this class.
*/
protected class Writer extends Thread
{
public void run ()
@@ -170,6 +222,10 @@ class Communicator
protected Socket _socket;
protected DataInputStream _din;
protected DataInputStream _dout;
protected OutputStream _out;
protected Queue _msgq = new Queue();
/** We use this to frame our upstream messages. */
protected FramingOutputStream _fout;
protected DataOutputStream _dout;
}
@@ -0,0 +1,31 @@
//
// $Id: DObject.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.dobj;
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;
public class DObject extends TypedObject
{
public static short TYPE = 400;
public short getType ()
{
return TYPE;
}
public void writeTo (DataOutputStream out)
throws IOException
{
}
public void readFrom (DataInputStream in)
throws IOException
{
}
}
@@ -0,0 +1,250 @@
//
// $Id: FramedInputStream.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.io;
import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import com.samskivert.util.StringUtil;
/**
* 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.
*
* <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). A new frame can be read at any
* time and will be appended to the data available (the frame length data
* is never inserted into the stream data), but it is assumed that the
* caller will want to read and process an entire frame before going on to
* read the next frame (so that <code>clear()</code> can be called in the
* event of a frame decoding failure without clearing out the data from
* subsequent frames).
*
* <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 single frame from the provided input stream and appends
* that data to the existing data available via the framed input
* stream's read methods.
*
* @return the length of the read frame in bytes.
*/
public synchronized int readFrame (InputStream source)
throws IOException
{
// first read in the frame length
if (source.read(_header, 0, HEADER_SIZE) < HEADER_SIZE) {
throw new EOFException();
}
// now decode the frame length
int flength = (_header[0] << 24) & 0xFF;
flength += (_header[1] << 16) & 0xFF;
flength += (_header[2] << 8) & 0xFF;
flength += _header[3] & 0xFF;
// expand our buffer to accomodate the frame data
int newcount = _count + flength;
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;
}
// read the data into the buffer
source.read(_buffer, _count, flength);
_count = newcount;
return flength;
}
/**
* Clears out any previously read frame data and reads a new frame
* into the buffer.
*
* @return the length of the read frame in bytes.
*/
public int clearAndReadFrame (InputStream source)
throws IOException
{
clear();
return readFrame(source);
}
/**
* Clears out any frame data already in the buffer including anything
* that hasn't yet been read.
*/
public void clear ()
{
_pos = 0;
_count = 0;
}
/**
* 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) {
return -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 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;
}
@@ -0,0 +1,123 @@
//
// $Id: FramingOutputStream.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.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 synchronized 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,8 +1,10 @@
//
// $Id: ObjectStreamException.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: ObjectStreamException.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.io;
import java.io.IOException;
/**
* The object stream exception is used to communicate an error in
* processing a typed object stream. As any error is fatal, we don't
@@ -10,7 +12,7 @@ package com.samskivert.cocktail.cher.io;
* 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 Exception
public class ObjectStreamException extends IOException
{
public ObjectStreamException (String message)
{
@@ -1,5 +1,5 @@
//
// $Id: TypedObjectFactory.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: TypedObjectFactory.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.io;
@@ -37,6 +37,28 @@ public class TypedObjectFactory
return msg;
}
/**
* 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
{
@@ -55,23 +77,6 @@ public class TypedObjectFactory
}
}
protected 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);
}
/** Our type to class mapping table. */
protected static HashMap _classes = new HashMap();
}
@@ -1,5 +1,5 @@
//
// $Id: AuthRequest.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: AuthRequest.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -9,23 +9,23 @@ import java.io.DataOutputStream;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
public class AuthenticationRequest extends UpstreamMessage
public class AuthRequest extends UpstreamMessage
{
/** The code for an object subscription request. */
/** The code for an auth request. */
public static final short TYPE = TYPE_BASE + 0;
/**
* Zero argument constructor used when unserializing an instance.
*/
public AuthenticationRequest ()
public AuthRequest ()
{
super();
}
/**
* Constructs a authentication request with the supplied credentials.
* Constructs a auth request with the supplied credentials.
*/
public AuthenticationRequest (Credentials creds)
public AuthRequest (Credentials creds)
{
_creds = creds;
}
@@ -50,8 +50,7 @@ public class AuthenticationRequest extends UpstreamMessage
}
/**
* The object id of the distributed object to which we are
* subscribing.
* The credentials associated with this auth request.
*/
protected Credentials _creds;
}
@@ -0,0 +1,72 @@
//
// $Id: AuthResponse.java,v 1.1 2001/05/22 21:51:29 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.dobj.DObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
/**
* The auth response communicates authentication success or failure as
* well as associated information via a distribted object transmitted
* along with the response. The distributed object simply serves as a
* container for the varied and manifold data involved in the
* authentication process.
*/
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.
*/
public AuthResponse ()
{
super();
}
/**
* Constructs a auth response with the supplied credentials.
*/
public AuthResponse (DObject data)
{
_data = data;
}
public DObject getData ()
{
return _data;
}
public short getType ()
{
return TYPE;
}
public void writeTo (DataOutputStream out)
throws IOException
{
super.writeTo(out);
_data.writeTo(out);
}
public void readFrom (DataInputStream in)
throws IOException
{
super.readFrom(in);
_data = (DObject)TypedObjectFactory.readFrom(in);
}
protected DObject _data;
}
@@ -1,5 +1,5 @@
//
// $Id: DownstreamMessage.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: DownstreamMessage.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -12,7 +12,7 @@ import com.samskivert.cocktail.cher.io.TypedObjectFactory;
* client. Downstream messages include object subscription, event
* forwarding and session management.
*/
public class DownstreamMessage
public abstract class DownstreamMessage extends TypedObject
{
/**
* All downstream message derived classes should base their typed
@@ -43,30 +43,15 @@ public class DownstreamMessage
// register our downstream message classes
static {
TypedObjectFactory.registerClass(AuthenticationRequest.TYPE,
AuthenticationRequest.class);
TypedObjectFactory.registerClass(SubscribeRequest.TYPE,
SubscribeRequest.class);
TypedObjectFactory.registerClass(FetchRequest.TYPE,
FetchRequest.class);
TypedObjectFactory.registerClass(UnsubscribeNotification.TYPE,
UnsubscribeNotification.class);
TypedObjectFactory.registerClass(ForwardEventNotification.TYPE,
ForwardEventNotification.class);
TypedObjectFactory.registerClass(PingNotification.TYPE,
PingNotification.class);
TypedObjectFactory.registerClass(LogoffNotification.TYPE,
LogoffNotification.class);
TypedObjectFactory.registerClass(AuthResponse.TYPE,
AuthResponse.class);
TypedObjectFactory.registerClass(EventNotification.TYPE,
EventNotification.class);
TypedObjectFactory.registerClass(ObjectResponse.TYPE,
ObjectResponse.class);
TypedObjectFactory.registerClass(FailureResponse.TYPE,
FailureResponse.class);
TypedObjectFactory.registerClass(PongNotification.TYPE,
PongNotification.class);
}
/** The code for an event notification. */
public static final byte EVENT = 0x00;
/** The code for a fetch/subscribe object response. */
public static final byte OBJECT = 0x01;
/** The code for a request failure. */
public static final byte FAILURE = 0x02;
/** The code for a pong response. */
public static final byte PONG = 0x03;
/** The code for an end of transmission notification. */
public static final byte EOT = 0x04;
}
@@ -1,8 +1,15 @@
//
// $Id: EventNotification.java,v 1.1 2001/05/22 06:07:59 mdb Exp $
// $Id: EventNotification.java,v 1.2 2001/05/22 21:51:29 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.dobj.Event;
import com.samskivert.cocktail.cher.dobj.EventFactory;
public class EventNotification extends DownstreamMessage
{
/** The code for an event notification. */
@@ -0,0 +1,50 @@
//
// $Id: FailureResponse.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
public class FailureResponse extends DownstreamMessage
{
/** The code for a logoff notification. */
public static final short TYPE = TYPE_BASE + 3;
/**
* Zero argument constructor used when unserializing an instance.
*/
public FailureResponse ()
{
super();
}
/**
* Constructs a failure response that is associated with the specified
* upstream message id.
*/
public FailureResponse (short messageId)
{
this.messageId = messageId;
}
public short getType ()
{
return TYPE;
}
public void writeTo (DataOutputStream out)
throws IOException
{
super.writeTo(out);
out.writeShort(messageId);
}
public void readFrom (DataInputStream in)
throws IOException
{
super.readFrom(in);
messageId = in.readShort();
}
}
@@ -0,0 +1,59 @@
//
// $Id: ObjectResponse.java,v 1.1 2001/05/22 21:51:29 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.dobj.DObject;
import com.samskivert.cocktail.cher.io.TypedObjectFactory;
public class ObjectResponse extends DownstreamMessage
{
/** The code for an event notification. */
public static final short TYPE = TYPE_BASE + 2;
/**
* Zero argument constructor used when unserializing an instance.
*/
public ObjectResponse ()
{
super();
}
/**
* Constructs an object response with supplied distributed object that
* is associated with the specified upstream message id.
*/
public ObjectResponse (short messageId, DObject dobj)
{
this.messageId = messageId;
_dobj = dobj;
}
public short getType ()
{
return TYPE;
}
public void writeTo (DataOutputStream out)
throws IOException
{
super.writeTo(out);
out.writeShort(messageId);
_dobj.writeTo(out);
}
public void readFrom (DataInputStream in)
throws IOException
{
super.readFrom(in);
messageId = in.readShort();
_dobj = (DObject)TypedObjectFactory.readFrom(in);
}
/** The object which is associated with this response. */
protected DObject _dobj;
}
@@ -0,0 +1,23 @@
//
// $Id: PongResponse.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
public class PongNotification extends DownstreamMessage
{
/** The code for a pong notification. */
public static final short TYPE = TYPE_BASE + 4;
/**
* Zero argument constructor used when unserializing an instance.
*/
public PongNotification ()
{
super();
}
public short getType ()
{
return TYPE;
}
}
@@ -1,5 +1,5 @@
//
// $Id: UpstreamMessage.java,v 1.1 2001/05/22 06:08:00 mdb Exp $
// $Id: UpstreamMessage.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -87,8 +87,8 @@ public abstract class UpstreamMessage extends TypedObject
// register our upstream message classes
static {
TypedObjectFactory.registerClass(AuthenticationRequest.TYPE,
AuthenticationRequest.class);
TypedObjectFactory.registerClass(AuthRequest.TYPE,
AuthRequest.class);
TypedObjectFactory.registerClass(SubscribeRequest.TYPE,
SubscribeRequest.class);
TypedObjectFactory.registerClass(FetchRequest.TYPE,
@@ -1,5 +1,5 @@
//
// $Id: UsernamePasswordCreds.java,v 1.1 2001/05/22 06:08:00 mdb Exp $
// $Id: UsernamePasswordCreds.java,v 1.2 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.net;
@@ -7,7 +7,7 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class UsernamePasswordCreds
public class UsernamePasswordCreds extends Credentials
{
public static final short TYPE = TYPE_BASE + 0;
@@ -0,0 +1,75 @@
//
// $Id: FrameTest.java,v 1.1 2001/05/22 21:51:29 mdb Exp $
package com.samskivert.cocktail.cher.io.test;
import java.io.*;
import com.samskivert.cocktail.cher.io.*;
public class FrameTest
{
public static void writeFrames (OutputStream out)
throws IOException
{
FramingOutputStream fout = new FramingOutputStream();
DataOutputStream dout = new DataOutputStream(fout);
// create a few frames and write them to the output stream
dout.writeUTF("This is a test.");
dout.writeUTF("This is only a test.");
dout.writeUTF("If this were not a test, there would be " +
"meaningful data in this frame and someone " +
"would probably be enjoying themselves.");
fout.writeFrameAndReset(out);
dout.writeUTF("Now is the time for all good men to come to the " +
"aid of their country.");
dout.writeUTF("Every good boy deserves fudge.");
dout.writeUTF("The quick brown fox jumped over the lazy cow.");
fout.writeFrameAndReset(out);
dout.writeUTF("Third time is the charm.");
fout.writeFrameAndReset(out);
}
public static void readFrames (InputStream in)
throws IOException
{
FramedInputStream fin = new FramedInputStream();
DataInputStream din = new DataInputStream(fin);
// read the first frame
fin.readFrame(in);
System.out.println(din.readUTF());
System.out.println(din.readUTF());
System.out.println(din.readUTF());
System.out.println("This should be -1: " + fin.read());
// read the second frame
fin.readFrame(in);
System.out.println(din.readUTF());
System.out.println(din.readUTF());
System.out.println(din.readUTF());
System.out.println("This should be -1: " + fin.read());
// read the third frame
fin.readFrame(in);
System.out.println(din.readUTF());
System.out.println("This should be -1: " + fin.read());
}
public static void main (String[] args)
{
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
writeFrames(bout);
byte[] data = bout.toByteArray();
ByteArrayInputStream bin = new ByteArrayInputStream(data);
readFrames(bin);
} catch (IOException ioe) {
ioe.printStackTrace(System.err);
}
}
}