MCS-378 Lab 4: Communication Middleware

Due: December 15, 2009

Objective

Your will experiment with one particular communication middleware package, Java RMI. You may do this with a partner if you'd like. You will be fusing together two example programs from two different textbooks: the sliding 15-tile puzzle from Chapter 15 of Concrete Abstractions and the Publisher/Topic/Subscriber example RMI system from Chapter 10 of Operating Systems and Middleware. In this way, you will be able to produce a multi-user puzzle.

Downloading and Testing the Example Programs

Before you write any code of your own, you should make sure you can compile and run the two textbooks' code.

For the puzzle program from Concrete Abstractions, you will need to download Puzzle.java and TileActionListener.java. Of these, the main Puzzle.java program is a slight adaptation of the first version shown in the book: it was modified to run as a stand-alone application rather than as an applet in a web browser. The supporting file TileActionListener.java is copied verbatim from the book. (The full text of this book, by Max Hailperin, Barbara Kaiser, and Karl Knight, is now available for free from the web page.) You should be able to compile the two files using javac and then run java Puzzle; if all is well, a window will pop up in which you can click on the buttons to move the tiles. If multiple copies of the Puzzle are run, they will each function independently, as no communication is occurring.

For the RMI example, you will need to download all five files listed under Chapter 10 on the web site of programs from the textbook. Compile these using javac. Then run rmiregistry& to start a registry going and java TopicServer to register a server with it. In other windows you should now be able to use java Subscriber and java Publisher someMessage in order to communicate. Two important points about rmiregistry: (1) when you run it, your current directory should be the directory containing your class files; (2) you should kill it before leaving the lab.

Making the Puzzle Communicate

Your primary goal for the lab is to merge into the Puzzle and TileActionListener classes some code like that in the Subscriber and Publisher classes, so that multiple instances of the puzzle will communicate. In particular, every time a user clicks one of the buttons on one of the puzzles, it will publish a message describing which button was clicked. All the puzzles (itself included) will receive this message as subscribers and will respond to the pushed tile.

There are two possible approaches you can take for the messages sent between the puzzles (by way of the TopicServer):

  1. You could create a TilePosition class that contains two integers, a row number and a column number. Instances of this class would be sent between the puzzles to indicate which button was clicked. This will require changing the MessageRecipient interface and the TopicServer class to use TilePosition in place of String for the messages. In order to be conveyed using RMI, the TilePosition class will need to implement the interface java.io.Serializable.

  2. You could communicate using Strings, which would allow the RMI code from the textbook to be unchanged. When the puzzle wants to publish a message describing the row and column that was clicked, it can join them together into a String, with a space in between, using code like row + " " + col. When the puzzle (in its role as subscriber) receives a message, it will need to read the two integers out of the String; the easiest way to do this is using the class java.util.Scanner.

The first approach will be slightly more efficient, as it does not need to translate the integers into decimal digits and back. The second approach has the advantage that the Subscriber and Publisher classes can be used to eavesdrop on, and butt into, the puzzles' conversation, which is handy for debugging.

When you have used either approach to integrate RMI communication into the puzzle, you should be able to run several instances of java Puzzle and find that they all operate in tandem; clicking on any one affects them all. (This assumes you have the rmiregistry and TopicServer running.)

Dealing with Late-Arriving Puzzles

Your code from the prior part of the lab should work well as long as all the puzzles start running before any user clicks on any of their buttons. However, if after clicking some buttons to rearrange the tiles, you start another copy of the puzzle running, you will see that it is out of synch with the others. Its tiles are in the initial configuration, unlike the tiles in the other puzzles. Clicking on buttons in either the new puzzle or one of the old ones will affect the others, but since the arrangements of tiles start out different, they will continue to differ.

The simplest (if not best) solution to this problem is to replace the TopicServer with a TopicServerWithHistory. This new class should implement the same Topic interface, so you should be able to plug it in without changing anything else. The difference is that it keeps a history of all the published messages and whenever a new subscriber is added sends all of those previous messages to the new subscriber.

Write this class and demonstrate that when a puzzle is started, its tiles get pushed around to match the preexisting puzzles.

Lab Report and Possible Extensions

Your report should consist of printouts of your code for each Java file that you wrote or modified. You need not turn in anything other than this code.

If you are looking for additional excitement, I can think of many possible extensions to the lab. I list here just some examples. If multiple users are cooperating on a puzzle across the network, they likely would want to send textual messages back and forth as well, to coordinate their work; you could build a messaging facility into the puzzle. Accommodating late-comers by keeping a full history of past messages is inefficient; you could achieve the same goal in a different way. Right now, one sluggish subscriber can hold everybody up; you could modify the TopicServer to create a new thread for each message delivery, or you could use a pool of threads to achieve the same effect without so many thread creations.