Implementing Multiple Remote GUIs With RMI

Embed Size (px)

Citation preview

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    1/8

    Implementing Multiple Remote GUIs with RMI

    Copyright Gordon R. Durand, 1999-2000

    Technical or typographical errors? Please email me.

    You can downloadthe code for this article.

    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

    i mpor t j ava. r mi . *; publ i c i nt erf ace Hel l oI nt f extends Remot e { publ i c St r i ng get Gr eeti ng( ) t hr ows Remot eExcept i on;

    }

    Implement the interface in a class that extends UnicastRemoteObject

    i mpor t j ava. r mi . *; i mpor t j ava. r mi . ser ver. *; i mpor t j ava. rmi . regi str y. * ;

    publ i c cl ass Hel l oRmt ext ends Uni cast Remot eObj ect i mpl ements Hel l oI nt f {

    publ i c Hel l oRmt ( ) t hrows Remot eExcept i on {}

    publ i c St r i ng get Gr eet i ng( ) { return "Hel l o f r om Hel l oRmt ! " ;

    }

    publ i c st at i c voi d mai n ( St r i ng[ ] ar gs) {Hel l oRmt r emot e;

    Syst em. set Secur i t yManager( new RMI Secur i t yManager( ) ) ;

    t r y {

    Locat eRegi st r y. cr eateRegi st r y(Regi st r y. REGI STRY_PORT) ;r emot e = new Hel l oRmt ( ) ;Nami ng. r ebi nd("Hel l oRmt ", r emot e) ;

    } cat ch ( Except i on e) {

    e. pr i nt St ackTr ace( ) ;}

    System. out . pr i nt l n( "Hel l oRmt bound i n regi st r y" ) ;

    }}

    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

    publ i c cl ass Hel l oRMI { publ i c st at i c voi d mai n ( St r i ng[ ] ar gs) {

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    2/8

    Hel l oI nt f r emot e = nul l ;

    t r y {r emot e = ( Hel l oI nt f ) Nami ng. l ookup ( "Hel l oRmt ") ;Syst em. out . pr i nt l n( r emot e. get Gr eet i ng( ) ) ;

    } cat ch ( Except i on e) {e. pr i nt St ackTr ace( ) ;

    }}

    }

    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

    >j avac *. j ava

    Generate the stub class with rmic

    >r mi c - v1. 2 Hel l oRmt

    Create a text file called policy with your security policy

    gr ant {/ / Al l ow ever yt hi ng f or nowper mi ssi on j ava. secur i t y. Al l Per mi ssi on;

    };

    Then start HelloRmt in its own window

    >st ar t "Hel l oRmt " j ava - Dj ava. secur i t y. pol i cy=pol i cy Hel l oRmt

    Wait until you see the "HelloRmt bound in registry" message and then start HelloRMI

    >j ava Hel l oRMIHel l o f r om Hel l oRmt !

    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.

    You Want Fries With That?

    RMI can do even more. It can request the bytecodes for the classes themselves. If an RMI call returns a

    reference to a class unknown to the local VM, the VM will first try to load the class from the local classpath.

    Failing that, it will request the class from the remote object's codebase, typically through an HTTP GET.

    This ability to ship an object's behavior along with the object itself makes RMI an extremely powerful tool

    for distributed applications.

    You don't even need a full scale HTTP server. With Java, you can write your own class server with just a

    few lines of code.

    A ClassServer would create a ServerSocket to listen on a specified port

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    3/8

    server = new Ser ver Socket ( por t ) ;

    and then wrap itself in a Thread to wait for a request

    pr i vat e voi d newLi st ener( ) {( new Thread( t hi s) ) . st ar t ( ) ;

    }

    The heart of the ClassServer is in its run method

    publ i c voi d run() {

    Socket socket ;

    t r y {socket = ser ver . accept ( ) ;

    } catch ( I OExcept i on e) {e. pr i nt St ackTr ace( ) ;

    return;}

    newLi st ener ( ) ;t r y {

    Dat aOut put St r eam out = new DataOut put St r eam( socket . getOut putSt r eam( ) ) ; t r y {

    Buf f eredReader i n = new Buf f eredReader( new I nput St r eamReader ( socket. getI nput St r eam( ) ) ) ;

    St r i ng path = get Pat h( i n) ;byt e[ ] bytecodes = get Byt es( pat h) ;Syst em. out . pr i nt l n( "Sendi ng " + socket. get I netAddr ess( ) + " " + path) ;

    t r y {out . wr i t eByt es( "HTTP/ 1. 0 200 OK\ r \ n") ;out . wr i t eByt es( "Cont ent - Lengt h: " + bytecodes. l engt h + "\ r \ n") ;out . wr i t eByt es( "Cont ent - Type: appl i cat i on/ j ava\ r \ n\ r\ n" ) ;

    out . wr i t e(byt ecodes) ;out . f l ush( ) ;

    } cat ch ( I OExcept i on i oe) {i oe. pri nt St ackTr ace( ) ;

    return; / / execut i on wi l l actual l y go t o f i nal l y bl ock f i rst}

    } cat ch ( Except i on e) {out . wr i t eBytes(" HTTP/ 1. 0 400 " + e. getMessage() + " \ r \ n") ;out . wr i t eBytes(" Cont ent - Type: t ext / ht ml \ r \ n\ r \ n") ;out . f l ush() ;

    }} catch ( I OExcept i on ex) {

    ex. pr i nt St ackTr ace( ) ;} f i nal l y {

    t r y {socket . cl ose( ) ;

    } cat ch ( I OExcept i on e) {}

    }}

    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.

    Skinny Client Fattens Up

    Since RMI can request bytecodes when it needs them, a remote GUI only needs to know about a single

    remote method. Suppose a GUIServer implements

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    4/8

    publ i c i nt erf ace GUI Ser ver I nt f extends Remot e { publ i c Panel getGui Panel ( ) t hrows Remot eExcept i on;

    }

    A GUIClient only needs to request a GuiPanel and display it

    Panel panel ;

    t r y {

    panel = ( Panel ) gui Server . get Gui Panel ( ) ;} cat ch ( RemoteExcept i on e) {

    e. pr i nt St ackTr ace( ) ;}

    i f ( panel ! = nul l ) {add( panel ) ;panel . set Vi si bl e( tr ue) ;

    }

    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

    publ i c abst r act cl ass Remot eGUI ext ends Panel publ i c abst r act voi d set up( St r i ng host ) ;

    GUIClient can cast the object reference to a RemoteGUI and call its setup method

    t r y {panel = ( RemoteGUI ) gui Server . getGui Panel ( ) ;

    } cat ch ( RemoteExcept i on e) {e. pr i nt St ackTr ace( ) ;

    } i f ( panel ! = nul l ) {

    panel . set up( host ) ;add( panel ) ;panel . set Vi si bl e( true) ;

    }

    Second, since GUIPanel extends RemoteGUI which extends Panel, it can't also extendUnicastRemoteObject, so it can't handle remote method calls itself. It might be better, anyway, to

    encapsulate that functionality in another class

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    5/8

    publ i c cl ass GUI Panel Rmt extends Uni cast Remot eObj ect i mpl ements GUI Panel I nt f { / / . . . al l the gory det ai l s here.

    And have GUIPanel create GUIPanelRmt in its setup method

    publ i c voi d set up( St r i ng host ) { t r y {

    r mt = new GUI Panel Rmt ( thi s, name, host ) ;} catch ( RemoteExcept i on e) {

    e. pr i nt St ackTr ace( ) ;}

    }

    Handling Multiple Clients

    In order for a server to handle multiple GUIs we must first give each new instance of GUIPanel a unique

    name

    s tat i c i nt panel Count = 0;

    publ i c Panel getGui Panel ( ) t hrows Remot eExcept i on {St r i ng name = "GUI Panel " + panel Count++;

    r eturn new GUI Panel ( name) ;}

    Then, in GUIPanel's setup routine, when we call GUIPanelRmt's constructor, GUIPanelRmt can register

    itself in a local registry with its unique name

    Nami ng. r ebi nd( name, t hi s) ;

    and then call a remote method on the server side

    St r i ng l ocal Host = ( I net Addr ess. get Local Host ( ) ) . get Host Addr ess( ) ;gui Ser ver . addGUI ( l ocal Host + "/ " + name) ;

    which will add its remote reference to a Vector of remote references

    pr i vat e Vect or gui s;

    publ i c voi d addGUI ( St r i ng name) t hr ows Remot eExcept i on { t r y {Obj ect gui = Nami ng. l ookup ( " rmi : / / " + name) ;gui s. add( gui ) ;

    } catch ( Except i on e) {e. pr i nt St ackTr ace( ) ;

    }}

    Finally, whenever the server side object's state changes, it broadcasts a message to all registered GUIs

    publ i c voi d updat eGUI s( i nt l en) {GUI Panel I nt f gui ;

    I t erator i = gui s . i t erator ( ) ;

    whi l e ( i . hasNext ( ) ) {gui = ( GUI Panel I nt f ) i . next ( ) ;

    t r y {

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    6/8

    gui . updat eGUI ( l en) ;} cat ch ( RemoteExcept i on e) {

    i . r emove( ) ;}

    }}

    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 sendssetLength 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

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    7/8

    Diagram 2: Multiple Remote GUIs return to text

    Diagram 3: Remote GUI Classes return to text

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html

    8 12/27/2012 7:16 PM

  • 8/22/2019 Implementing Multiple Remote GUIs With RMI

    8/8

    lementing Multiple Remote GUIs with RMI http://grdurand.com/java/rmi.html