![]() |
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:
This file's name isimport java.rmi.*; public interface WSI extends Remote { public String read() throws RemoteException; }
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:
We need to note that: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); } }
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.
The applet needs to have access to theimport 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()); } } }
_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