Democratic Chat System

Unfortunately these binary downloads don't work, my only guess is that there is some kind of ".class" to mime type mapping that the WAM web server doesn't have. This "looks just like" versions at that do work... Some years ago Chris Torek did a version of the Unix chat program that allowed more than two people to chat together. His version used a server process. At that time I worked out some simple algorithms to implement group chat without using a server process. Each participant has a vector of the other participants and sends the chat text to each of them. Of course, the challenge here is to keep the various participant vectors consistent and synchronized. The reliable nature of the Java RMI mechanism can help in this.

The call is:

	java Phone -myuserid callee@host
Where myuserid is optional and defaults to the "" property, and callee@host is optional. There are also commands to connect and disconnect, etc. It first tries to register on a RMI registry on the current machine with the userid given, but it does not die if the registration fails. Note that if the registration does fail the instance cannot be connected to but can only connect to other successfully registered instances.

The important thing to know to understand how this works is that new participants apply to an existing participant for permission to enter the conversation. The act of giving permission causes a reply to the new participant containing the vector of existing participants, and also causes messages to be sent to all existing participants informing them of the new participant.

For example, suppose Alice, Bob, and Charlie are in an existing conversation and Dave wants to join. He uses the RMI registry to lookup Alice and sends an Apply message containing his own object. If Alice decides to allow Dave to join, she returns her object and Bob and Charlies objects in the result of the Apply message. This gets Dave all the information he needs to be included. Alice also sends Sponsor messages to Bob and Charlie so they can add Dave into their copy of the participant vector.

One extension I made to the algorithm I worked out twenty years ago was to allow multiple objects on the apply call as well as in the return value. This, with some extra support code, allows a person already in a conversation to include a new person (by passing the existing vector in the call) and even for two conversations to merge (by having one participant in one conversation include one person in the second conversation). In this case multiple objects are passed both in the apply call and the apply result. This also requires the sponsor message to be able to pass multiple objects.

It is not clear that the RMI registry is a good fit for this kind of lookup. With this simple-minded implementation a second user using the same userid silently steals the registration from an initial user of that userid. I suppose I could try looking up the userid before registering for it but I'm not sure of the registry semantics vis-a-vis objects that have gone away without explicitly releasing their binding. Note that this program does not release its name binding when it quits.

I was able to banish the "deprecated interface" message on the DataInputStream by replacing it with a BufferedReader containing an InputStreamReader. Somehow this was not obvious from reading the web stuff on IO enhancements, but I did find this substitution somewhere in the JavaSoft web, and it seems to work. We are still using the available() trick but for some reason it does not get passed through so I have to do available() on then read from the BufferedReader.

The code in transfer() was supposed to be the start of a polymorphic data transfer scheme. The general idea was to figure out what type was passed and do the right thing with it:

	if ( thing instanceof String ) {
		String s = (String) thing;
		System.err.println(f + ": " + s);
	} else if ( thing instanceof Sound) {
		LocalPlaySound( (Sound) thing );	// Etc
	} else if ( thing instanceof BinaryFileTransfer ) {
		ReceiveBinaryFile( (BinaryFileTransfer) thing);
	} else {
		System.err.println("Unknown thing from '" + f + "'");
But there are two things one might want to polymorph on: the type of the data being passed and the kind of interface receiving it. For example, a text-based program like this one would want to do different things than a GUI-based program. It is not yet obvious to me how to structure this code to achieve the right kind of polymorphism. For example, if the if instanceof nest is replaced by object polymorphism it is not obvious to me whether this would involve additional RMI calls back to the sending object, which is not what we want to do (expecially since we have all the code right here, in another instance of exactly the same object).
Back to ZBEN's home page.