The call is:
java Phone -myuserid callee@hostWhere myuserid is optional and defaults to the "user.name" 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 System.in 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).