|
CS 696 Emerging Technologies: Distributed Objects |
|
---|
Spring Semester, 1998
RMI and Web
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 17, RMI and Web
- References
- Jar Files
- RMI Hello World via Web
- Example - No Jar
- Hello.java
- HelloServer.java
- HelloApplet.java - The client
- hello.html
- File Structure, URL Etc.
- Example - With Jar
- helloJar.html
- RMI and Browsers
- Activator Tags for IE
- Activator Tags for Netscape
- Activator Tags for Netscape and IE
- Bootstraping the Client
- java-rmi.cgi
- Loading the client
- LoadClient.java
- MySecurityManager.java
- HelloClient.java
- RMI and Firewalls
Java RMI Specification
Java RMI: Remote Method Invocation by Downing, IDG Books, 1998, Appendix A, pp 259-260
See http://www.dsu.edu/doc/jdk1.1/docs/tooldocs/solaris/jar.html
for the documentation on using the jar command
Information about applet tags can be found at:
http://jva.sun.com/products/jdk/1.1/docs/guide/misc/applet.html
Information
about Activator tags can be found at:
http://developer.javasoft.com/developer/earlyAccess/activator/ja-tag.html
A jar file is basically a files that are zipped into one file with a manifest,
or table of contents
The jar program allows you to bundle Java classes together
This can be useful in distributing programs like RMI clients
See http://www.dsu.edu/doc/jdk1.1/docs/tooldocs/solaris/jar.html
for the documentation on using the jar command
Example of Using jar
Directory Structure on Rohan
package jarExample;
public class HiMom
{
public void message()
{
System.out.println( "Hi Mom" );
}
}
package jarExample;
public class MyMain
{
public static void main( String[] args )
{
HiMom test = new HiMom();
test.message();
}
}
Compiling with -d option
In directory jarExampleSrc compile using:
javac -d .. *.java
The -d flag indicates the base directory to place the .class files
So we get:
Since the classes are in the jarExample package the .class files are placed in
the base subdirectory jarExample
Using Jar
In directory whitney I use the following command to create a jar file:
jar -cf hi.jar jarExample
Since
the classes are in a package they must be stored in the jar file in the
jarExample directory
I then place /home/ma/whitney/java/classes/whitney/hi.jar in my classpath
I can now run the program with:
java jarExample.MyMain
The Classes
package whitney.rmi.examples.applet;
public interface Hello extends java.rmi.Remote
{
String sayHello() throws java.rmi.RemoteException;
}
package whitney.rmi.examples.applet;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.UnicastRemoteObject;
import java.io.IOException;
import java.rmi.server.*;
import java.net.InetAddress;
import sdsu.util.ProgramProperties;
public class HelloServer
extends UnicastRemoteObject
implements Hello
{
public HelloServer() throws RemoteException {}
public String sayHello()
{
return "Hello World from " + getHostName();
}
protected static String getHostName()
{
try
{
return InetAddress.getLocalHost().getHostName();
}
catch (java.net.UnknownHostException who)
{
return "Unknown";
}
}
//HelloServer.java - Continued
public static void main(String args[])
{
// Create and install a security manager
System.setSecurityManager(new RMISecurityManager());
try
{
ProgramProperties flags =
new ProgramProperties( args );
int port = flags.getInt( "p", 1099 );
String serverLabel = "HelloServer";
HelloServer serverObject = new HelloServer();
Registry localRegistry =
LocateRegistry.createRegistry(port);
localRegistry.rebind( serverLabel, serverObject);
System.out.println("HelloServer bound in registry");
}
catch (Exception e)
{
System.out.println("HelloServer err: ");
e.printStackTrace();
}
}
}
package whitney.rmi.examples.applet;
import java.awt.*;
import java.rmi.*;
public class HelloApplet extends java.applet.Applet
{
String message = "";
public void init()
{
try
{
String serverAddress = getParameter( "server" );
message = message + "After getParameter: ";
Hello obj = (Hello)Naming.lookup( serverAddress );
message = obj.sayHello();
}
catch (Exception e)
{
message += "HelloApplet exception:\n " +
e.getMessage();
}
}
public void paint(Graphics g)
{
g.drawString(message, 25, 50);
}
}
<HTML>
<title>Hello World</title>
<center> <h1>Hello World</h1> </center>
The message from the HelloServer is:
<p>
<applet codebase="."
code="whitney.rmi.examples.applet.HelloApplet"
width=500 height=120>
<PARAM NAME="server"
VALUE="//www.eli.sdsu.edu:5555/HelloServer">
</applet>
</HTML>
Information
about applet tags can be found at:
http://jva.sun.com/products/jdk/1.1/docs/guide/misc/applet.html
URL to hello.html:
http://www.eli.sdsu.edu/rmi-web/hello.html
In my public html directory on www.eli in the directory
rmi-web
I have:
- code.jar (for next example)
- hello.html (for this example)
- helloJar.html (for next example)
- whitney/
In rmi-web/whitney/rmi/examples/applet I have:
Hello.class | HelloServer.class |
Hello.java | HelloServer.java |
HelloApplet.class | HelloServer_Skel.class |
HelloApplet.java | HelloServer_Stub.class |
HelloClient.java | HelloClient.class (for another example) |
This runs accessing the URL:
http://www.eli.sdsu.edu/rmi-web/hello.html
using the appletveiwer on a Macintosh
You must type xstdcmap -all at the shell prompt before you run
appletviewer and have it display on an NCD X-terminal in the BAM labs
In this example all classes needed on the client side (Hello.class,
HelloApplet.class, HelloServer_Stub.class) are placed in a jar file and
downloaded using the archive tag
This is much faster than having the files downloaded one at a time
This example is run by accessing the URL:
http://www.eli.sdsu.edu/rmi-web/helloJar.html
<HTML>
<title>Hello World</title>
<center> <h1>Hello World</h1> </center>
The message from the HelloServer is:
<p>
<applet codebase="."
archive="code.jar"
code="whitney.rmi.examples.applet.HelloApplet"
width=500 height=120>
<PARAM NAME="server" VALUE="//www.eli.sdsu.edu:5555/HelloServer">
</applet>
</HTML>
To run an applet that uses RMI the browser must support RMI
There was an RMI release that worked with Java 1.0.2
Microsoft has a .zip file to use with IE4.0 to allow rmi to work with IE, see
htt://www.microsoft.com/msdn/services/subscription/msdn_unsup-ed.htm
Netscape Communicator & RMI
To be done later
Activator
Sun's solution to the different browsers is Activator, which replaces the
browser's Java VM with a Sun Java VM which supports java 1.1.5
See http://java.sun.com/proucts/activator/index.html
for more information and to download activator
To use activator, it must be installed on the client machine and the applet tag
needs to be modified
To work with the activator for IE the applet tag:
<applet codebase="."
code="whitney.rmi.examples.applet.HelloApplet"
width=500 height=120>
<PARAM NAME="server"
VALUE="//www.eli.sdsu.edu:5555/HelloServer">
</applet>
Needs to be changed to:
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="500" height="120"
codebase="http://java.sun.com/activator/Jinstall_ea3.cab#Version=1,0,3,0">
<PARAM NAME="code"
VALUE="whitney.rmi.examples.applet.HelloApplet">
<PARAM NAME="codebase" VALUE=".">
<PARAM NAME="type"
VALUE="application/x-java-applet;version=1.1">
<PARAM NAME="server"
VALUE="//www.eli.sdsu.edu:5555/HelloServer">
No JDK 1.1 support for APPLET!!
</OBJECT>
To work with the activator for Netscape the applet tag:
<applet codebase="."
code="whitney.rmi.examples.applet.HelloApplet"
width=500 height=120>
<PARAM NAME="server"
VALUE="//www.eli.sdsu.edu:5555/HelloServer">
</applet>
Needs to be changed to:
<EMBED type="application/x-java-applet;version=1.1"
width="500" height="120"
code="whitney.rmi.examples.applet.HelloApplet"
codebase="."
server="//www.eli.sdsu.edu:5555/HelloServer"
pluginspage="http://java.sun.com/products/activator/ea3/plugin-install.html">
<NOEMBED>
No JDK 1.1 support for APPLET!!
</NOEMBED>
</EMBED>
To work with the activator for IE the applet tag given on the previous slide
needs to be changed to:
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
width="500" height="120"
codebase="http://java.sun.com/activator/Jinstall_ea3.cab#Version=1,0,3,0">
<PARAM NAME="code"
VALUE="whitney.rmi.examples.applet.HelloApplet">
<PARAM NAME="codebase" VALUE=".">
<PARAM NAME="type"
VALUE="application/x-java-applet;version=1.1">
<PARAM NAME="server"
VALUE="//www.eli.sdsu.edu:5555/HelloServer">
<COMMENT>
<EMBED type="application/x-java-applet;version=1.1"
width="500" height="120"
code="whitney.rmi.examples.applet.HelloApplet"
codebase="."
server="//www.eli.sdsu.edu:5555/HelloServer"
pluginspage="http://java.sun.com/products/activator/ea3/plugin-install.html">
<NOEMBED>
</COMMENT>
No JDK 1.1 support for APPLET!!
</NOEMBED>
</EMBED>
</OBJECT>
Activator Tags for Everywhere
This get to be a bit complicated and uses javascript
For more information see:
http://developer.javasoft.com/developer/earlyAccess/activator/ja-tag.html
In RMI you can have all the classes for the client machine downloaded from the
server machine when you want to run the client
This is relatively slow
Users may not like downloading code which is then run on their machines
This requires a web server on the server machine
Most web servers require a cgi program to forward the request to the rmi
system
The cgi program must be in a file called "java-rmi.cgi" and must be in top
level cgi bin directory
The following java-rmi.cgi program does the forwarding
This program can be found in the rmi-users mailing list archive and Java RMI: Remote Method Invocation by Downing, IDG Books, 1998, Appendix A, pp 259-260
#!/bin/sh
# This file handles rmi requests to download RMI code
# The work is done by the class:
# sun.rmi.transport.proxy.CGIHandler
# This class supports a QUERY_STRING of the form
# "forward=<port>" with a REQUEST_METHOD of "POST"
# The body of the request will be forwarded to the server (
# as aPOST request) to the port given in the URL. The response
# will be returned to the orginal requester.
# Set the path to include the location of the jdk to run
PATH=/opt/java/bin:$PATH
java \
-DAUTH_TYPE=$AUTH_TYPE \
-DCONTENT_LENGTH=$CONTENT_LENGTH \
-DCONTENT_TYPE=$CONTENT_TYPE \
-DDOCUMENT_ROOT=$DOCUMENT_ROOT \
-DGATEWAY_INTERFACE=$GATEWAY_INTERFACE \
-DHTTP_ACCEPT="$HTTP_ACCEPT" \
-DHTTP_CONNECTION=$HTTP_CONNECTION \
-DHTTP_HOST=$HTTP_HOST \
-DHTTP_USER_AGENT="$HTTP_USER_AGENT" \
-DPATH_INFO=$PATH_INFO \
-DPATH_TRANSLATED=$PATH_TRANSLATED \
-DQUERY_STRING=$QUERY_STRING \
-DREMOTE_ADDR=$REMOTE_ADDR \
-DREMOTE_HOST=$REMOTE_HOST \
-DREMOTE_IDENT=$REMOTE_IDENT \
-DREMOTE_USER=$REMOTE_USER \
-DREQUEST_METHOD=$REQUEST_METHOD \
-DSCRIPT_NAME=$SCRIPT_NAME \
-DSERVER_NAME=$SERVER_NAME \
-DSERVER_PORT=$SERVER_PORT \
-DSERVER_PROTOCOL=$SERVER_PROTOCOL \
-DSERVER_SOFTWARE=$SERVER_SOFTWARE \
sun.rmi.transport.proxy.CGIHandler
The following program, LoadClient, bootstraps the client code for the class:
whitney.rmi.examples.applet.HelloClient and then runs the client
This program is to be run on the client machine
Do not refer to any of the client classes directly in this program,
If you refer to them the class loader will try to load them from the local
machine and throw an exception when it can not find them
import java.rmi.RMISecurityManager;
import java.rmi.server.RMIClassLoader;
import java.net.URL;
public class LoadClient
{
public static void main( String[] args)
{
System.setSecurityManager(new MySecurityManager());
try
{
URL codeBaseURL = new URL(
"http://www.eli.sdsu.edu/rmi-web/");
String clientClassName =
"whitney.rmi.examples.applet.HelloClient";
System.out.println( "Try To load class");
Class clientClass =
RMIClassLoader.loadClass(codeBaseURL,
clientClassName );
System.out.println( clientClass.getName() );
Runnable client = (Runnable) clientClass.newInstance();
System.out.println( "Run client");
client.run();
}
catch ( Exception allErrors )
{
System.out.println( "LoadClient Exception: " );
allErrors.printStackTrace();
}
}
}
This security manager allows the downloading of classes
import java.rmi.*;
public class MySecurityManager extends RMISecurityManager
{
public synchronized void checkAccess(Thread t) {}
public synchronized void checkAccess(ThreadGroup g) {}
public synchronized void checkConnect(String h, int p) {}
public synchronized void checkConnect(String h, int p,
Object o) {}
public synchronized void checkRead(String f, Object c) {}
public synchronized void checkRead(String f) {}
}
Here is the actual client program that is run
package whitney.rmi.examples.applet;
import java.rmi.*;
public class HelloClient implements Runnable
{
public void run()
{
try
{
String server = "rmi://roswell.sdsu.edu:5555/HelloServer";
Hello remote = (Hello) Naming.lookup( server );
String message = remote.sayHello();
System.out.println( message );
}
catch ( Exception error)
{
error.printStackTrace();
}
}
}
When a RMI connection hits a firewall, the transport layer will embed the RMI
call in a HTTP POST request and the return information is sent back in the body
of the HTTP response
If the firewall proxy will forward an HTTP request directed to an arbitrary
port on the host machine, then request is sent to the proper RMI port
- The transport layer on that port handles the decoding of the HTTP
POST
If the firewall proxy will only forward an HTTP request to well-known HTTP
ports, then the call will be forwarded to the HTTP (web) server listening on
port 80 of the host machine
- The web server will need the java-rmi.cgi program to route the connection
Connections routed through HTTP are at least an order of magnitude slower than
normal connections
In JDK 1.2 you can specify which port a remote will listen on, to allow you to
configure firewalls to allow RMI requests through
visitors since 10-Mar-98