Professional Documents
Culture Documents
Implementing Multiple Remote GUIs With RMI
Implementing Multiple Remote GUIs With RMI
http://grdurand.com/java/rmi.html
Introducing RMI
The Remote Method Invocation API allows Java objects to send messages to Java objects running in other Java Virtual Machines anywhere on a TCP/IP network. Declare the remote methods in an interface which extends the Remote interface
import java.rmi.*; public interface HelloIntf extends Remote { public String getGreeting() throws RemoteException; }
Notice that HelloRmt's constructor throws a RemoteException, but does nothing else. HelloRmt's main method does all the work. First we install a SecurityManager. Then we create a Registry object (most RMI examples run the registry in a separate process, but it's not necessary). Finally, we create the remote object and bind it to a name in the Registry. Now we need a client to test the remote object
public class HelloRMI { public static void main (String[] args) {
1 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
HelloIntf remote = null; try { remote = (HelloIntf) Naming.lookup ("HelloRmt"); System.out.println(remote.getGreeting()); } catch (Exception e) { e.printStackTrace(); } } }
HelloRMI never actually gets instantiated. A static main method does all the work. First it calls Naming.lookup, which returns a reference to a Remote type. It casts that to the HelloIntf type, and call its getGreeting method. The RMI implementation does the rest, calling the remote object's getGreeting method, serializing the returned String, and delivering it back to HelloRMI. Compile the classes with javac
>javac *.java
Wait until you see the "HelloRmt bound in registry" message and then start HelloRMI
>java HelloRMI Hello from HelloRmt!
You can see that RMI can make remote objects appear to be local. RMI can also serialize objects (such as our return String) and send them over the network as the parameters and return values of remote methods.
2 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
On receiving a request, the ClassServer spins off a new Thread to continue listening, and then parses the input stream for a GET header and a class file name. It reads the class file and send the bytecodes, along with the appropriate header, as a response to the GET.
3 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
public interface GUIServerIntf extends Remote { public Panel getGuiPanel() throws RemoteException; }
When GUIClient request a GUIPanel, the GUIServer instantiates the class, serializes it (and all the objects it references), and returns a reference to GUIClient. GUIClient, finding itself with a reference to an unknown object which itself references other unknown objects, attempts to load the bytecodes for those objects. When it fails to find them in the local classpath, it GETs them from a remote ClassServer. The beauty of this scenario is that the GUIClient always gets fresh bytecodes in their latest revision, without the user ever needing to update GUIClient itself. See Diagram 1: GUI Server
Setting Up Communications
Since GUIPanel brings its own cohorts and their behavior with it, it can look up Remote objects on the server to make calls home, and even set up a remote object on the client side to handle callbacks from the server. A couple minor problems must be overcome. First, because GUIPanel's constructor is actually called on the server side (prior to it being serialized and sent to the client), you don't want to attempt to set up communications in the constructor. Rather, you need a setup() method that the GUIClient can call once GUIPanel gets to the client side. In order to do this you'll have to have your GUI panel extend RemoteGUI, which extends Panel
public abstract class RemoteGUI extends Panel public abstract void setup(String host);
GUIClient can cast the object reference to a RemoteGUI and call its setup method
try { panel = (RemoteGUI) guiServer.getGuiPanel(); } catch (RemoteException e) { e.printStackTrace(); } if (panel != null) { panel.setup(host); add(panel); panel.setVisible(true); }
Second, since GUIPanel extends RemoteGUI which extends Panel, it can't also extend UnicastRemoteObject, so it can't handle remote method calls itself. It might be better, anyway, to encapsulate that functionality in another class
4 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
public class GUIPanelRmt extends UnicastRemoteObject implements GUIPanelIntf { // ... all the gory details here.
Then, in GUIPanel's setup routine, when we call GUIPanelRmt's constructor, GUIPanelRmt can register itself in a local registry with its unique name
Naming.rebind(name, this);
Finally, whenever the server side object's state changes, it broadcasts a message to all registered GUIs
public void updateGUIs(int len) { GUIPanelIntf gui; Iterator i = guis.iterator(); while (i.hasNext()) { gui = (GUIPanelIntf) i.next (); try {
5 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
Notice that if we get an exception in the broadcasting loop, we simply remove that reference from our Vector, as a quick-and-dirty way of handling GUI termination without implementing a removeGUI method. See Diagram 2: Multiple Remote GUIs
A Complete Demonstration
You can download the code for a complete demonstration of a GUIServer/GUIClient which supports multiple remote GUIs. On the server side we have a GUIServer and a ClassServer. On the client side we start with a simple GUIClient. The server side has a JBoard object which interacts with remote JBoardGUls. The adapter classes which actually handle the RMI methods are JBoardRmt on the server side and JBoardGUIRmt on the client side. The GUI has a slider which adjusts a value in a text box. Changing the value in the JBoardGUI panel sends setLength messages via JBoardGUIRmt to JBoardRmt, which passes it on to JBoard. JBoard then sends a updateGUls message to JBoardRmt, which broadcasts updateLength messages to all GUIs. See Diagram 3: Remote GUI Classes
Notes
The java commands to start up GUIServer and GUIClient require some additional options. To simplify things, we put these commands into DOS batch files. To simplify further, we can create a shortcut to the batch files. Building the GUIServer and GUIClient class files involves a number of steps, including running the javac compiler, copying files, and running the rmic stub compiler. To simplify things, we put these commands into a batch file. If calls to Naming take longer than one or two seconds, it's not Java, it's a DNS lookup timeout problem. Edit your \winnt\system32\drivers\etc\hosts file to specify IP addresses for each machine involved.
Diagrams
Diagram 1: GUI Server return to text
6 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
return to text
return to text
7 of 8
12/27/2012 7:16 PM
http://grdurand.com/java/rmi.html
8 of 8
12/27/2012 7:16 PM