My purpose here is to strip RMI down to the simplest possible set up. In particular
- No security policy is used.
- All code is in copies a single jar file.
- There is no dynamic code loading.
- No separate rmiregistry process is needed.
There are no doubt some advantages to using an external registry process and dynamic code loading. However for many applications they just aren't needed.
The server code
My example code is an Othello game. The main server class is called RemoteGameModel. This class records the state of the game; I used the observer pattern to alert observers of any change to the state of the game. The observers are typically running in other JVM instances, possibly on other machines.The hookup of the observers to the RemoteGameModel is initiated by the observers; they will look up the RemoteGameModel using a registry. Thus after creating the RemoteGameModel in the server we need to register it in a registry running at a known location. This is done with a few lines of code in a main method in class ServerMain:
First we create the observable model. The RemoteGameModel classs extends UnicastRemoteObject, which means that as part of being constructed, the object is exported. Being exported is important since it means that when the object is passed to a remote object, a stub will be made for it and passed instead.
Second, we need a registry. Rather than using an rmiregistry process, it is easier to create a registry in the same JVM as the server object resides. This means the registry and the server must be on the same host. The port number used should be unique to your application.
Third, the RemoteGameModel is registered with the registry.
The next two lines report the URI that can be used to refer to the RemoteGameModel object.
There are a few things that can go wrong, so it's important to wrap the above code in try-catch.
The client code
On the client side, we need to obtain a reference to the RemoteGameModel which is on another machine. In RMI we ask the registry and the registry sends back a proxy (stub) object representing the server. The stub implements the RemoteGameModelInterface, just as does the actual RemoteGameModel.The following code is in the main method of class ClientMain:
First set a string to be the URI for the object.
Then the static method Naming.lookup returns the stub.
Once we have a reference to this object we can use it to send messages to the server object. In my code I use it to build an observer in the client. I pass the reference to the proxy into the constructor of the observer object. The last thing the observer does is to send addObserver(this) to the proxy. As the observer object's class extends UnicastRemoteObject, this sends a proxy for the observer over to the servers machine, where it is added to the server's list of observers.
Deploying and running the code
The code can now be tested simply by starting a JVM process running ServerMain.main and a number of processes running ClientMain.main.To make deployment easier, it is a good idea to put all files in a .jar file. I called mine othello-2.jar. Then the server can be started from the command line with the command
java -cp othello-2.jar othello.ServerMainAnd the clients can be run from the command line with the command
java -cp othello-2.jar othello.ClientMain
Further information and source code
Further information about the techniques used in the Othello project can be found at http://www.engr.mun.ca/~theo/Courses/sd/notes.html under "Animation with Threads" and "RMI and remote, concurrent observers". The source code at http://www.engr.mun.ca/~theo/Courses/sd/links.html shows the project at various stages of development:- Othello-0: Thread based animation.
- Othello-1: Adds concurrent observation and multiple view stragegies.
- Othello-2: The project is converted to use RMI.
- Othello-3: Adds input and game state to make a playable game.