18.3 Loading Classes at Runtime


All the client really has to know about the remote object is its remote interface. Everything else it needsfor instance, the stub classescan be loaded from a web server (though not an RMI server) at runtime using a class loader. Indeed, this ability to load classes from the network is one of the unique features of Java. This is especially useful in applets. The web server can send the browser an applet that communicates back with the server; for instance, to allow the client to read and write files on the server. However, as with any time that classes are loaded from a potentially untrusted host, they must be checked by a SecurityManager .

Unfortunately, while remote objects are actually quite easy to work with when you can install the necessary classes in the local client class path, doing so when you have to dynamically load the stubs and other classes is fiendishly difficult. The class path , the security architecture, and the reliance on poorly documented environment variables are all bugbears that torment Java programmers. Getting a local client object to download remote objects from a server requires manipulating all of these in precise detail. Making even a small mistake prevents programs from running, and only the most generic of exceptions is thrown to tell the poor programmers what they did wrong. Exactly how difficult it is to make the programs work depends on the context in which the remote objects are running. In general, applet clients that use RMI are somewhat easier to manage than standalone application clients . Standalone applications are feasible if the client can be relied on to have access to the same .class files as the server has. Standalone applications that need to load classes from the server border on impossible .

Example 18-6 is an applet client for the Fibonacci remote object. It has the same basic structure as the FibonacciClient in Example 18-5. However, it uses a TextArea to display the message from the server instead of using System.out .

Example 18-6. An applet client for the Fibonacci object
 import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.rmi.*; import java.math.BigInteger; public class FibonacciApplet extends Applet {   private TextArea  resultArea     = new TextArea("", 20, 72, TextArea.SCROLLBARS_BOTH);   private TextField inputArea  = new TextField(24);   private Button calculate = new Button("Calculate");   private String server;   public void init( ) {          this.setLayout(new BorderLayout( ));          Panel north = new Panel( );     north.add(new Label("Type a non-negative integer"));     north.add(inputArea);     north.add(calculate);     this.add(resultArea, BorderLayout.CENTER);     this.add(north, BorderLayout.NORTH);     Calculator c = new Calculator( );     inputArea.addActionListener(c);     calculate.addActionListener(c);     resultArea.setEditable(false);          server = "rmi://" + this.getCodeBase( ).getHost( ) + "/fibonacci";        }   class Calculator implements ActionListener {          public void actionPerformed(ActionEvent evt) {              try {         String input = inputArea.getText( );         if (input != null) {           BigInteger index = new BigInteger(input);                       Fibonacci f = (Fibonacci) Naming.lookup(server);           BigInteger result =  f.getFibonacci(index);           resultArea.setText(result.toString( ));         }       }        catch (Exception ex) {         resultArea.setText(ex.getMessage( ));       }               }   } } 

You'll notice that the rmi URL is built from the applet's own codebase . This helps avoid nasty security problems that arise when an applet tries to open a network connection to a host other than the one it came from. RMI-based applets are certainly not exempt from the usual restrictions on network connections.

Example 18-7 is a simple HTML file that can be used to load the applet from the web browser.

Example 18-7. FibonacciApplet.html
 <html> <head> <title>RMI Applet</title> </head> <body> <h1>RMI Applet</h1> <p> <applet align="center" code="FibonacciApplet" width="300" height="100"> </applet> <hr /> </p> </body> </html> 

Place FibonacciImpl_Stub.class , Fibonacci.class , FibonacciApplet.html , and FibonacciServer.class in the same directory on your web server. Add this directory to the server's class path and start rmiregistry on the server. Then start FibonacciServer on the server. For example:

 %  rmiregistry &  %  java FibonacciServer &  

Make sure that both of these are running on the actual web server machine. Many web server farms use different machines for site maintenance and web serving, even though both mount the same filesystems. To get past the applet security restriction, both rmiregistry and FibonacciServer have to be running on the machine that serves the FibonacciApplet.class file to web clients.

Now load FibonacciApplet.html into a web browser from the client. Figure 18-2 shows the result.

Figure 18-2. The Fibonacci applet

For applications, it's much easier if you can load all the classes you need before running the program. You can load classes from a web server running on the same server the remote object is running on, if necessary. To do this, set the java.rmi.server.codebase Java system property on the server (where the remote object runs) to the URL where the .class files are stored on the network. For example, to specify that the classes can be found at http://www.cafeaulait.org/rmi2/, you would type:

 %  java -Djava.rmi.server.codebase=http://www.cafeaulait.org/rmi2/  FibonacciServer & Fibonacci Server ready. 

If the classes are in packages, the java.rmi.server.codebase property points to the directory containing the top-level com or org directory rather than the directory containing the .class files themselves . Both servers and clients will load the .class files from this location if the files are not found in the local class path first.

Loading classes from the remote server makes the coupling between the server and the client a little less tight. However, any client program you write will normally have to know quite a bit about the system it's talking to in order to do something useful. This usually involves having at least the remote interface available on the client at compile time and runtime. Even if you use reflection to avoid that, you'll still need to know the signatures and something about the behavior of the methods you plan to invoke. RMI just doesn't lend itself to truly loose coupling like you might see in a SOAP or, better yet, RESTful server. The RMI design metaphor is more running one program on several machines than it is having several programs on different machines that communicate with each other. Therefore, it's easiest if both sides of the connection have all the code available to them when the program starts up.

Java Network Programming
Java Network Programming, Third Edition
ISBN: 0596007213
EAN: 2147483647
Year: 2003
Pages: 164

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net