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;You'll notice that the rmi URL
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( ));
}
}
}
}
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. FibonacciAppletl
<html>Place FibonacciImpl_Stub.class,
<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>
Fibonacci.class,
FibonacciAppletl, 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 &Make sure that both of these are running on the actual web server
% java FibonacciServer &
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 FibonacciAppletl into a web browser
from the client. Figure 18-2 shows the result.
Figure 18-2. The Fibonacci applet

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/If the classes are in packages, the
FibonacciServer & Fibonacci Server ready.
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.
• Table of Contents• Index• Reviews• Reader Reviews• Errata• AcademicJava Network Programming, 3rd EditionBy
Elliotte Rusty Harold Publisher: O'ReillyPub Date: October 2004ISBN: 0-596-00721-3Pages: 706
Thoroughly revised to cover all the 100+ significant updates
to Java Developers Kit (JDK) 1.5, Java Network
Programming is a complete introduction to
developing network programs (both applets and applications)
using Java, covering everything from networking fundamentals
to remote method invocation (RMI). It includes chapters on
TCP and UDP sockets, multicasting protocol and content
handlers, servlets, and the new I/O API. This is the
essential resource for any serious Java developer.