COMP 310
Fall 2010

HW08:  RMI Chat Program

Home  Info  Owlspace  Resources

The goal of this assignment is to design and implement a flexible, extensible chat program using RMI.

Chat Program Requirements:

The chat program must be able to:

  1. Connect and communicate with any other student's implementation (including the staff's).
  2. Support two-way text chatting with
    1. Multiple, simultaneous single individuals
  3. Support an "auto-connect-back" feature wherein an accepted request to chat is automatically connected without the user having to know the requestor's address.
  4. Support the ability to handle new kinds of data packets at run-time, e.g. images, files, etc. without initially having ability.
  5. Be easily extensible to handle the transimission and reception of any arbitrary data type.  (Related to #4)
  6. Gracefully handle (i.e. not crash) the reception of an unknown data type.
  7. To join the group chat only requires a single manual connection to a single existing participant.

Get the provided library packages:   

This includes:

Get the ChatApp API common interfaces (API) packages

This includes the latest version of the common interfaces and additional documentation developed by the class.   ALL students' code MUST adhere to the API defined by the comp310f10 package!   The code in this package will change often, so be sure to perform an "Update to Head" frequently!

In the comp310f10 package is also an HTML web page document that gives additional API information.   The information in this document is part of your required specifications!

The class will be designing the major interfaces needed to communicate with another ChatApp implementation.   Class attendence is mandatory!   The current version of those interfaces will be available through a second svn:externals link.   Each student is responsible for knowing the results of all class and lab design discussions.

A discussion forum and chat room have been set up in Owlspace to facilitate out-of-class design discussions.  And as always, one can send a message to the class at comp310f10 at owlspace-ccm.rice.edu.

This project requires more code writing than any previous assignment, so START EARLY!!!    There are also numerous implementation pitfalls due to RMI and due to possibly poor design by the class.   Find these early and submit bring them up for discussion right away so that they can be addressed and fixed in a reasonable time.   Since interoperability is a requirement for this assignment, no one is coding in a vacuum, don't keep things to yourself!   

Resources:

Tips and Traps

Don't Remove A User While Traversing the List of Users

If you send everyone, including yourself, an IRemoveUser data packet, you will remove a user (yourself) from the list of users, as the chat room is traversing the that same list as it sends the data packet to every user.   But removing an element from a collection as you are traversing it is asking for trouble because you will make the loop count erroneous, possibly causing elements of the collection (i.e. users) to be skipped.  

Solution:   Remove yourself from the chat room before telling the rest of the chat room to remove you.

Don't Serialize an Anonymous Inner Class

Unless, of course, you want Java to attempt to suck your entire ChatApp down a network hole.   'Nuff said.

Don't Use Static Classes and/or Fields

The hazy semantics of the inter-object relationships and closure issues that can arise can cause wildly unpredictable results.   Static anything in a network system is just plain bad news.   Stay away...far, far away.

Sometimes You Don't Want To Dispatch To a New Thread

Assuming that the call to IChatRoom.sendMsg() is a blocking call, it is not always desirable to make that call using another thread, as one would do to free the GUI thread from being blocked.   If you want to make sure that the message is sent before doing something else, call the sendMsg() method directly and let your current thread block on the call.   That will guarantee the next thing your thread does is after that call fully completes.

Note:  Depending on exactly what you are trying to accomplish, completely blocking the current thread may not be entirely desirable either, so you may wish to entertain other options as well, e.g. dispatching to a custom thread rather than the standard one that is used to send messages (see, for instance, below).   The key is to focus on the order of execution that you want for the tasks at hand.

Insuring that Tasks Are Executed After Sending A Message While on a Separate Thread

Sometime you want to do something definitively after sending a message to the chat room.   But the usual construct to dispatch the sending of a message to another thread to free the GUI thread doesn't allow other tasks to be performed in a manner that is definitively after the sending of the message.   If that's the sort of thing you need, try this modification:

Somewhere, define the following interface, which is simply a work-around the fact that Java will put a warning about generic parameters in arrays when we use a vararg parameter with a generically defined type:

/**
 * Convenience interface to get around type-erasure generated warnings about generic types in varargs.
 */
interface IVoidLambdaDP extends IVoidLambda {
}

Modify the standard "sendData" thread-dispatching method to take a vararg parameter of the above type:

	/**
	 * Send a data packet and process the returned data asynchronously on a new
	 * thread.  On that same thread, after the message is sent and the returned status
	 * objects processed, a vararg array of commands is run.  
	 * The data is the input parameter to the command's apply
	 * method which has a void return.  The vararg allows no commands as a 
	 * viable sendData call.
	 * 
	 * @param data
	 * @param cmds Vararg of commands to run after the message is sent and return status's processed.
	 */
	public void sendData(final ADataPacket data, final IVoidLambdaDP... cmds) {

		// spawn a new thread to handle the actual transmission, thus freeing
		// this thread to return.
		(new Thread() {
			public void run() {
				// Send the data packet to the chat room
				IStatus[] returnStatus = room.sendMsg(data, userStub);
				// process the returned value using a utility method
				processStatusArray(returnStatus, data);
				// Run the commands, if any, handing them the data.
				for (IVoidLambdaDP cmd : cmds) {
					cmd.apply(data);
				}
			}
		}).start(); // start the new thread
	}

A typical call would look like:

		sendData(data, new IVoidLambdaDP() {

			@Override
			public void apply(ADataPacket... params) {
				// do some stuff here.  Will be done after the data is sent.
			}
		});

Any number of IVoidLambdaDP's can be specified, including none and they will all get run.

 

The Return Value of myDataPacketAlgo.getCmd(id) Needs to be Downcast.

Because getCmd is a method inherited from AExtVisitorAlgo, the return type of getCmd is typed to be the superclass of ADataPacketAlgoCmd, namely IExtVisitorAlgoCmd. But an ADataPacketAlgo only allows ADataPacketAlgoCmds to be installed, so the return value can be safely downcast.  Your code should look something like this:

ADataPacketAlgoCmd<IStatus, ?, IUser> cmd = (ADataPacketAlgoCmd<IStatus, ?, IUser>) myDataPacketAlgo.getCmd(id);

This will generate an "unsafe cast" warning from the compiler, but just take the quick fix to add an "@SuppressWarnings("unchecked")" attribute to the enclosing method.

 

Passed Parameters and Fields Do NOT Behave the Same!

A common mistake is to pass a reference to the chat room to the connection object's constructor.   Later, the model's field that references the current chatroom is changed to be that of a new chat room.  But the connection object is unchanged and still internally refers to the old chat room because it does not reference the chatroom field of the model.   Using an anonymous inner class implementation of the connetion object neatly save the day here.   Why is it safe to use an anonymous inner class for IConnection?    What about IUser?   

 

 

Find more help at the Java How-To's web page.


Grading Criteria

 

 

 

 


© 2010 by Stephen Wong and Scott Rixner