|
CSCI A348/A548Lecture Notes 26 Fall 1999 |
We now understand RMI pretty well. There's not much we need to know in terms of how we think about our application: we do it as if the programs were all running on the same machine. That's the beauty of RMI. The difficulty is in the ancillary bookeeping: interface files, the need to run the RMI compiler, the necessity of being aware of the files that it creates in the process (and through which networking is actually done). All of this is apparent in the homework 7 exercise, where the client distribution and server start-up have to be done by hand: the client needs to get her/his client software, the server administrator needs to start the server before the clients can communicate with each other. Let's now revisit the weather applet application posted in lecture notes 23. The client (being an applet) will be distributed autimatically. The server-side will be implemented with servlets, and thus we won't need to worry about it having to be started by hand any longer. The first time the servlet is needed it will be started and will make the state of the weather on our host available to the world by RMI. That's the plan for today's lecture.
The first thing we need to do is to:
1. Create an interface
that defines the exported methods that the remote server will implement.
Let's call this the Weather Server Interface (WSI) and place it in the
servlet area.
Here's the code:
import java.rmi.*;
public interface WSI
extends Remote
{
public String read() throws RemoteException;
}
This file's name is WSI.java and we place it
in the servlet area. Now we need to write the servlet.
2. Define a
servlet that implements the interface just described. The servlet
should either subclass UnicastRemoteObject or implement
the Remote interface. Other than declaring its remote
methods to throw RemoteException objects the remote
object does not need to do anything special to allow its methods
to be invoked remotely.
Here's the code:
import java.io.*;
import java.net.*;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class WS
extends HttpServlet
implements Remote, WSI
{
public String read()
{
return "The time is:\n ***("
+ new java.util.Date().toString()
+ ")***\n... and the weather is fine.";
}
public void init(ServletConfig conf)
throws ServletException
{
super.init(conf);
try {
Registry reg;
UnicastRemoteObject.exportObject(this);
try {
reg = LocateRegistry.getRegistry(39904);
reg.list();
} catch (Exception e) {
reg = null;
}
if (reg == null) {
try {
reg = LocateRegistry.createRegistry(39904);
} catch (Exception e) { }
}
try {
reg.rebind("Letterman", this);
} catch (Exception e) {
}
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
public void doGet(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException, IOException
{
resp.setContentType("text/html");
resp.getWriter().println(
"<html><head><title>Letterman's Applet</title></head>"
+ "<body bgcolor=white>"
+ "<applet codebase=http://tucotuco.cs.indiana.edu:59904/lab14"
+ "\ncode=WA width=400 height=300> </applet></body></html>"
);
}
public void doPost(HttpServletRequest req,
HttpServletResponse resp)
throws ServletException,
IOException
{
doGet(req, resp);
}
}
We need to note that:
3. Write a program that creates an instance of your remote server. Export the object making it available for use by clients by registering the object by name with a registry service.
We've done this already in
init() because we don't create an instance of the servlet, the
web server does, and when it creates it that's the method that it calls:
init(). So we move to the next step:
4. Compile the servlet
(with javac) and use rmic to generate the stub
and skeleton for the remote object. Invoke rmic on the
remote object class (not interface). It creates and compiles two new
classes, with the suffixes _Stub and _Skel.
IMPORTANT NOTE
Set your CLASSPATH variable now to:
setenv CLASSPATH .:/l/jdk1.1/lib/classes.zip:/l/jsdk2.0/lib/jsdk.jarin your
.login file and source it
(or log out and log back in
after you make the change). Now compile
the files as
discussed (with javac) then run rmic on the
server class.
5. The next step in the RMI registry is a comment on the registry
used. You can either run the rmiregistry program (not
recommended here) or have the remote server object act as its own
registry server. It actually does it nicely, and we'll discuss that
in class. So as far as this step is related again we don't need to
do anything more than what we've already done. Now it's time to
write the applet.
6. Now you can write
a client program that uses the remote object that is exported by the
server. This will be an applet and we need to look into the servlet's
doGet() method to find out the name of the class and the
location, relative to the web server's htdocs directory.
import java.rmi.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class WA
extends Applet
implements ActionListener
{
private TextArea status;
WSI server;
private Button request;
public void init()
{
add (status = new TextArea(5, 50));
add (request = new Button("Retrieve"));
status.setEditable(false);
status.setText("Starting Connection");
request.addActionListener(this);
try {
server = (WSI)Naming.lookup("rmi://"
// protocol used
+ getCodeBase().getHost()
// location of registry server
+ ":39904"
// your 3990x port here
+ "/Letterman"
// remote server's name
);
} catch (Exception e) {
System.out.println("Error: " + e.toString());
status.setText("Error: " + e.toString());
}
}
public void actionPerformed (ActionEvent e) {
try {
status.setText(server.read() + "\n"); // replaced append
} catch (RemoteException ex) {
status.setText("Error: " + ex.toString());
}
}
}
The applet needs to have access to the _Stub class and the
server interface so we either copy them to the applet's location or create
soft links to them there. Then compile the applet. Now we're ready for any incoming calls.
Summary of steps taken:
WSI.java in jserv/servlets
WS.java in jserv/servlets
javac W*.java in jserv/servlets)
rmic WI (in jserv/servlets)
to get WS_Skel.class and WS_Stub.class
WA.java in apache_1.3.9/htdocs/lab14
apache_1.3.9/htdocs/lab14
ln -s /u/dgerman/November/jserv/servlets/WS_Stub.class WS_Stub.class ln -s /u/dgerman/November/jserv/servlets/WSI.class WSI.classto the classes that the client class needs to use
javac WA.java)
the client applet in apache_1.3.9/htdocs/lab14
http://tucotuco.cs.indiana.edu:59904/servlet/WSand work with the resulting client applet