(where/u/username/httpd/htdocs/weather
username
is your username) and work inside it.
Also use your hostname (where I use tucotuco
) and your
second port number, which is your regular 198xx
port number with the leading 1
replaced with 2
(in my case: 29800
), for this application and lab only.
Note that you have to use the port number both in the client and
the application.
Lab 10: Weather Station by Java RMI
We will implement/simulate a client/server weather station in the lab using Java RMI.
Assume we have a computer system (this will
be tucotuco.cs.indiana.edu
for me) that is physically
connected to all sorts of weather-monitoring equipment: rain gauges,
thermometer, anemometer, barometer, and so on. This will be our server
system; it monitors the temperature and weather in the burrow cluster.
We will let our users connect to our web server, get an applet (that will start running on their system) and use the applet to query the weather server (which is a Java application we'll write) to obtain the current weather in the area monitored by the server (i.e., the burrow cluster).
The first thing we need to clarify, if we are going to use remote method invocations, is what methods our server will export. This happens to be the first in the list of steps that we have listed as necessary in order to produce a RMI application:
1. Create an interface that defines the exported methods that the remote object implements (that is, the methods that the server implements and that clients can invoke remotely). This interface extends theSo here's the interface:java.rmi.Remote
interface.Each method in the interface must be declared to throw a
java.rmi.RemoteException
which is the superclass of many more specific RMI exception classes.
This means that our Java server will export one method,tucotuco.cs.indiana.edu% cat weatherInf.java
import java.rmi.*; public interface weatherInf extends Remote { public String read() throws RemoteException; } tucotuco.cs.indiana.edu%
read
.
Here's the Java application that will implement the weather server.
It implements the interface just described.
This covers steps 2 and 3 in our RMI recipe:tucotuco.cs.indiana.edu% cat weatherInfImpl.java
import java.rmi.*; import java.rmi.server.*; import java.rmi.registry.*; public class weatherInfImpl extends UnicastRemoteObject implements weatherInf { public String read() { System.out.println("Sending Data..."); return "The time is: " + new java.util.Date().toString() + "... and the weather is fine."; } public weatherInfImpl() throws RemoteException { System.out.println("Initializing Weather Server"); } public static void main (String args[]) { Registry reg; System.setSecurityManager(new RMISecurityManager()); try { weatherInfImpl WII = new weatherInfImpl(); reg = LocateRegistry.createRegistry(29800); // your port here reg.bind("WeatherInfo", WII); System.out.println("Server Ready"); } catch (RemoteException e) { System.out.println("General Server Error: " + e); System.exit(0); } catch (AlreadyBoundException e) { System.out.println("Name is already bound: " + e); System.exit(0); } } }
2. Define a subclass ofjava.rmi.server.UnicastRemoteObject
that implements yourRemote
interface. This class represents the remote object (or server object). Other than declaring its remote methods to throwRemoteException
objects, the remote object does not need to do anything special to allow its methods to be invoked remotely. TheUnicastRemoteObject
and the rest of the RMI infrastructure handle this automatically.3. Write a program (a 'server') that creates an instance of your remote object. Export the object, making it available for use by clients, by registering the object by name with a registry service. This is usually done with the
java.rmi.Naming
class and the rmiregistry program. A server program may also act as its own registry server by using theLocateRegistry
class andregistry
interface of thejava.rmi.registry
package.
Now we compile the server and its interface:
And then steps 4 and 5 in the recipe read:tucotuco.cs.indiana.edu% ls -l total 10 -rw-r--r-- 1 dgerman students 179 Nov 4 09:53 info.html -rw-r--r-- 1 dgerman students 934 Nov 4 10:05 weatherApplet.java -rw-r--r-- 1 dgerman students 116 Nov 4 09:55 weatherInf.java -rw-r--r-- 1 dgerman students 1027 Nov 4 10:37 weatherInfImpl.java
tucotuco.cs.indiana.edu% javac weatherInf.java weatherInfImpl.java
tucotuco.cs.indiana.edu%
4. After you compile the server program (with javac) use rmic to generate a 'stub' and 'skeleton' for the remote object. Invoke rmic with the name of the remote object class (not the interface) on the command line. It creates and compiles two new classes with the suffixesWith RMI the client and the server do not communicate directly. On the client side the client's reference to a remote object is implemented as an instance of a 'stub' class. When the client invokes a remote method, it is a method of this stub object that is actually called. The stub does the necessary networking to pass the invocation to a 'skeleton' class on the server. This skeleton translates the networked request into a method invocation on the server object, and passes the returned value back to the stub, which passes it back to the client. This can be a complicated system but fortunately application programmers never have to think about stubs and skeletons; they are generated automatically by the rmic tool._Stub
and_Skel
.
tucotuco.cs.indiana.edu% rmic weatherInfImpl
tucotuco.cs.indiana.edu% ls -l total 24 -rw-r--r-- 1 dgerman students 179 Nov 4 09:53 info.html -rw-r--r-- 1 dgerman students 934 Nov 4 10:05 weatherApplet.java -rw-r--r-- 1 dgerman students 273 Nov 4 13:30 weatherInf.class -rw-r--r-- 1 dgerman students 116 Nov 4 09:55 weatherInf.java -rw-r--r-- 1 dgerman students 1599 Nov 4 13:30 weatherInfImpl.class -rw-r--r-- 1 dgerman students 1027 Nov 4 10:37 weatherInfImpl.java -rw-r--r-- 1 dgerman students 1489 Nov 4 13:57 weatherInfImpl_Skel.class -rw-r--r-- 1 dgerman students 1856 Nov 4 13:57 weatherInfImpl_Stub.class tucotuco.cs.indiana.edu%
5. If the server uses the default registry service provided by theIn this lab we use the second method, in the October 27 lecture we used the default registry service.Naming
class you must run the registry server, if it is not already running. You can run the registry server by invoking the rmiregistry program. Note however that, as we mentioned at step 3 a server program may also act as its own registry server by using theLocateRegistry
class and registry interface of thejava.rmi.registry package
so you need to run the registry server (or make sure it is running) only if the server uses the default registry service provided by theNaming
class.
We can now write the client (an applet):
tucotuco.cs.indiana.edu% cat weatherApplet.java
import java.rmi.*; import java.applet.*; import java.awt.*; public class weatherApplet extends Applet { private TextArea status; weatherInf WI; public void init() { add (status = new TextArea(5, 50)); add (new Button("Retrieve")); status.setEditable(false); status.setText("Starting Connection"); try { WI = (weatherInf)Naming.lookup( "rmi://" + getCodeBase().getHost() + ":29800/WeatherInfo" ); // your 298xx port here } catch (Exception e) { System.out.println("Error: " + e.toString()); status.setText("Error: " + e.toString()); } } public boolean handleEvent (Event e) { if (e.target instanceof Button && e.id == Event.ACTION_EVENT) { try { status.setText(WI.read() + "\n"); // replaced append } catch (RemoteException ex) { status.setText("Error: " + ex.toString()); } } return false; } }
tucotuco.cs.indiana.edu%
Notes from the recipe's step 6:
1. The client must first obtain a reference to the remote object exported by the server by using theWe now compile the client:Naming
class to look up the object by name.2. The name is typically an
rmi:
URL.3. The remote remote reference that is returned is an instance of the
Remote
interface for the object (or more specifically a 'stub' object for the remote object). Once this client has this remote object it can invoke methods on it exactly as it would invoke the methods of a local object.4. The only thing that it must be aware of is that all remote methods can throw
RemoteException
objects, and that in the presence of network errors, this can happen at unexpected times.5. RMI uses the serializaton mechanism to transfer the stub object from the server to the client. Because the client may load an untrusted stub object, it should have a security manager installed to prevent a malicious (or just buggy) stub from deleting files or otherwise causing harm. The
RMISecurityManager
class is a suitable security manager that all RMI clients should install.
Prepare a way of distributing it:
tucotuco.cs.indiana.edu% javac weatherApplet.java
Note: weatherApplet.java uses a deprecated API. Recompile with "-deprecation" for details. 1 warning tucotuco.cs.indiana.edu%
And start the server:tucotuco.cs.indiana.edu% cat info.html
<html> <head> <title> RWI (Remote Weather Info) </title> </head> <body bgcolor=white> <applet code=weatherApplet.class width=400 height=300> </applet> </body> </html>
tucotuco.cs.indiana.edu%
Run it (but please use a very recent version of Netscape Navigator/Communicator).tucotuco.cs.indiana.edu% ps PID TTY TIME CMD 11546 pts/1 0:01 csh tucotuco.cs.indiana.edu% netstat -a | grep 29800 tucotuco.cs.indiana.edu% java weatherInfImpl & [1] 14369 tucotuco.cs.indiana.edu% Initializing Weather Server Server Ready tucotuco.cs.indiana.edu% ps -f UID PID PPID C STIME TTY TIME CMD dgerman 14369 11546 6 14:28:04 pts/1 0:03 /usr/bin/../java/bin/../bin/sparc/native_threads/java weatherInfImpl dgerman 11546 11531 0 09:39:04 pts/1 0:01 -csh tucotuco.cs.indiana.edu%