Title: RMI
1RMI
- From OReilly RMI text and internet tutorials
2Other rmi tutorials
- http//java.sun.com/developer/onlineTraining/rmi/R
MI.html - And
- http//java.sun.com/docs/books/tutorial/rmi/
3RMI
- The Java Remote Method Invocation (RMI) system
allows an object running in one Java Virtual
Machine (VM) to invoke methods on an object
running in another Java VM. RMI provides for
remote communication between programs written in
the Java programming language.
4A little background
- Your RMI application will consist of several
files, generally. - Server side usually at least two files
- An interface which implements remote and which
defines a function (or more) - A class implementing the interface
- Maybe a separate server which registers the
remote services and delivers them to clients - Client-side applet or html or servlet to deliver
requested method invocations
5A little background
- Since the client needs to know the name of, and
signature of, the method she invokes, a method
stub file needs to be available to the client
(in the class path for client) showing how to
marshal and unmarshal parameters and return
types. - The rmi compiler (rmic in your java directory)
creates someclass_stub.class files which are
provided to your client.
6Port for rmi
- To run registry on Windows platforms
- start rmiregistry
- By default, the registry runs on TCP port 1099.
To start a registry on a different port, specify
the port number from the command line. For
example, to start the registry on port 2001 on a
Windows platform - start rmiregistry 2001
7First a tutorial example
- http//java.sun.com/j2se/1.5.0/docs/guide/rmi/hell
o/hello-world.html51 - A VERY simple working rmi example
8Hello interface(extends remote)
- package example.hello
- import java.rmi.Remote
- import java.rmi.RemoteException
- public interface Hello extends Remote
- String sayHello() throws RemoteException
-
9Client
- package example.hello
- import java.rmi.registry.LocateRegistry//usual
RMI imports - import java.rmi.registry.Registry
- public class Client
- private Client()
- public static void main(String args)
- String host (args.length lt 1) ? null
args0 - try
- Registry registry LocateRegistry.getRegistr
y(host) - Hello stub (Hello) registry.lookup("Hello")
- String response stub.sayHello()
- System.out.println("response " response)
- catch (Exception e)
- System.err.println("Client exception "
e.toString()) - e.printStackTrace()
-
-
-
10The RMI Server (sometimes called
ServiceImpllike HelloImpl in this case)
- package example.hello
- import java.rmi.registry.Registry
- import java.rmi.registry.LocateRegistry
- import java.rmi.RemoteException
- import java.rmi.server.UnicastRemoteObject
- public class Server implements Hello
- public Server()
- public String sayHello()
- return "Hello, world!"
- public static void main(String args)
- try
- Server obj new Server()
- Hello stub (Hello) UnicastRemoteObject.expo
rtObject(obj, 0) - // Bind the remote object's stub in the
registry - Registry registry LocateRegistry.getRegistr
y() - registry.bind("Hello", stub)
- System.err.println("Server ready")
- catch (Exception e)
- System.err.println("Server exception "
e.toString())
11Compile then run
- First compile Hello.java, then the other two
files. - Start rmiregistry
- Run server
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
example/hello/Server - Response is Server ready
- Run client
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
example/hello/Client - response Hello, world!
12Same interfacebut using an applet
- The impl file
- import java.rmi.Naming
- import java.rmi.RemoteException
- import java.rmi.RMISecurityManager
- import java.rmi.server.UnicastRemoteObject
- public class HelloImpl extends
UnicastRemoteObject implements Hello - public HelloImpl() throws RemoteException
- super()
- public String sayHello()
- return "Hello World!"
- public static void main(String args)
- // Create and install a security manager
- if (System.getSecurityManager() null)
- System.setSecurityManager(new
RMISecurityManager()) -
- try
- HelloImpl obj new HelloImpl()
13The policy file
- JRE did not seem to look at the
jre/lib/security/java.policy file in the JRE
directory so I used my own policy file - grant
- //to handle rmi connection issues
- permission java.net.SocketPermission
"localhost1024-", "listen,connect,resolve"
14Run the impl file specifying policy at runtime
- c\PROGRA1\Java\JDK151.0_0\bingtjava
-Djava.security.manager -Djava.security.policypol
icy.all HelloImpl - HelloServer bound in registry
15Hello applet rmi example files
- Hello.htmlusual file points to applet.class, I
put it in webapps/ROOT - HelloApplet a jdk1.1 applet that gets a HelloInt
object bound in the registry - HelloImpl remote thingy implementing the hello
interface. - Remember to javac and rmic the HelloImpl file and
put both the class and the stub class files in
the directory with your applet code - I did not use packages from the example and had
to modify a few other minor items.
16RMI
- I started RMI registry from my java directory,
not from tomcat. - I did not use a policy file for the application
program. - I ran the example in Netscape not IE
- A batchfile to set classpath to some webapp and
then start rmi - Set classpathC\PROGRA1\TOMCAT1.5\WEBAPPS\ROOT
- C\PROGRA1\TOMCAT1.5\WEBAPPS\ROOT\WEB-INF\classe
s - rmiregistry
17The tutorial url for this example
- http//java.sun.com/j2se/1.3/docs/guide/rmi/getsta
rt.doc.html5238
18Run the applet (the little hello world is the
message)
19Windows rmi info
- rmiregistry - The Java Remote Object Registry
- The rmiregistry command starts a remote object
registry on the specified port on the current
host. - rmiregistry port
- The rmiregistry command creates and starts a
remote object registry on the specified port on
the current host. If port is omitted, the
registry is started on port 1099. The rmiregistry
command produces no output and is typically run
in the background. For example start rmiregistry
20Windows rmi info
- A remote object registry is a bootstrap naming
service that is used by RMI servers on the same
host to bind remote objects to names. Clients on
local and remote hosts can then look up remote
objects and make remote method invocations. - The registry is typically used to locate the
first remote object on which an application needs
to invoke methods. That object in turn will
provide application-specific support for finding
other objects.
21Windows rmi info
- The methods of the java.rmi.registry.LocateRegistr
y class are used to get a registry operating on
the local host or local host and port. - The URL-based methods of the java.rmi.Naming
class operate on a registry and can be used to
look up a remote object on any host, and on the
local host bind a simple (string) name to a
remote object, rebind a new name to a remote
object (overriding the old binding), unbind a
remote object, and list the URLs bound in the
registry. - OPTIONS
- -J
- Used in conjunction with any java option, it
passes the option following the -J (no spaces
between the -J and the option) on to the java
interpreter. - SEE ALSO
- java, java.rmi.registry.LocateRegistry and
java.rmi.Naming
22The calculator project interface file
- public interface Calculator
- extends java.rmi.Remote
- public long add(long a, long b)
- throws java.rmi.RemoteException
-
- public long sub(long a, long b)
- throws java.rmi.RemoteException
-
- public long mul(long a, long b)
- throws java.rmi.RemoteException
-
- public long div(long a, long b)
- throws java.rmi.RemoteException
-
23The calculator project implementation class
- public class CalculatorImpl extends
java.rmi.server.UnicastRemoteObject - implements Calculator
- // Implementations must have an
- //explicit constructor
- // in order to declare the
- //RemoteException exception
- public CalculatorImpl()
- throws java.rmi.RemoteException
- super()
-
- public long add(long a, long b)
- throws java.rmi.RemoteException
- return a b
-
- public long sub(long a, long b)
- throws java.rmi.RemoteException
- return a - b
-
-
24The calculator project run rmic on
CalculatorImpl to generate stub file
- C\PROGRA1\JAVA\JDK151.0_0\BINgtdir
Calculator. - Volume in drive C has no label.
- Volume Serial Number is 84F7-99D3
- Directory of c\PROGRA1\Java\JDK151.0_0\bin
- 10/24/2006 0133 PM 271
Calculator.class - 10/24/2006 0133 PM 405
Calculator.java - 10/24/2006 0135 PM 536
CalculatorImpl.class - 10/24/2006 0135 PM 815
CalculatorImpl.java - 10/24/2006 0137 PM 2,476
CalculatorImpl_Stub.class - 5 File(s) 4,503 bytes
- 0 Dir(s) 142,396,870,656 bytes
free - C\PROGRA1\JAVA\JDK151.0_0\BINgt
25The calculator project the server for the rmi
- import java.rmi.Naming
- public class CalculatorServer
- public CalculatorServer()
- try
- Calculator c new CalculatorImpl()
- Naming.rebind("rmi//localhost1099/Calcula
torService", c) - catch (Exception e)
- System.out.println("Trouble " e)
-
-
- public static void main(String args)
- new CalculatorServer()
-
26Calculator client class
- import java.rmi.NotBoundException
- public class CalculatorClient
- public static void main(String args)
- try
- Calculator c (Calculator)
- Naming.lookup("rmi//lo
calhost/CalculatorService") - System.out.println( c.sub(4, 3) )
- System.out.println( c.add(4, 5) )
- System.out.println( c.mul(3, 6) )
- System.out.println( c.div(9, 3) )
- catch (MalformedURLException murle)
- System.out.println()
- System.out.println(
- "MalformedURLException")
- System.out.println(murle)
- catch (RemoteException re)
- System.out.println()
- System.out.println("RemoteException")
- System.out.println(re)
27Running the calculator project
- You are now ready to run the system! You need to
start three consoles, one for the server, one for
the client, and one for the RMIRegistry. - Start with the Registry. You must be in the
directory that contains the classes you have
written. From there, enter the following - rmiregistry
- If all goes well, the registry will start running
and you can switch to the next console. - In the second console start the server hosting
the CalculatorService, and enter the following - gtjava CalculatorServer
- It will start, load the implementation into
memory and wait for a client connection. - In the last console, start the client program.
- gtjava CalculatorClient
- If all goes well you will see the following
output - 1 9 18 3
- That's it you have created a working RMI system.
Even though you ran the three consoles on the
same computer, RMI uses your network stack and
TCP/IP to communicate between the three separate
JVMs. This is a full-fledged RMI system.
28Screenshot of calculator
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
CalculatorClient - 1
- 9
- 18
- 3
- C\PROGRA1\JAVA\JDK151.0_0\BINgt
29A note
- This simple example is redone at the end using
the simplifiedservlethandler and
loggingservletforwarder implementing rmi through
http tunneling
30Computing somethinglike pi
- http//java.sun.com/docs/books/tutorial/rmi/design
ing.html
31Compiling compute.java and task.java and creating
a jar file in compute directory
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjavac
compute\compute.java - C\PROGRA1\JAVA\JDK151.0_0\BINgtjavac
compute\task.java - C\PROGRA1\JAVA\JDK151.0_0\BINgtjar cvf
compute.jar compute\.class - added manifest
- adding compute/Compute.class(in 238) (out
169)(deflated 28) - adding compute/Task.class(in 166) (out
139)(deflated 16)
32Jar files
- C\PROGRA1\JAVA\JDK151.0_0\BIN\PUBLIC1\CLASSESgt
jar xvf compute.jar - created META-INF/
- inflated META-INF/MANIFEST.MF
- inflated compute/Compute.class
- inflated compute/Task.class
- C\PROGRA1\JAVA\JDK151.0_0\BIN\PUBLIC1\CLASSESgt
33Compile client files
- C\PROGRA1\JAVA\JDK151.0_0\BIN\PUBLIC1\CLASSESgt
javac c\progra1\java\jdk151 - .0_0\bin\client\ComputePi.java
- C\PROGRA1\JAVA\JDK151.0_0\BIN\PUBLIC1\CLASSESgt
javac c\progra1\java\jdk151.0_0\bin\client\Comp
utePi.java - C\PROGRA1\JAVA\JDK151.0_0\BIN\PUBLIC1\CLASSESgt
javac c\progra1\java\jdk151.0_0\bin\client\Pi.j
ava
34Start rmi registery
- C\PROGRA1\JAVA\JDK151.0_0gtstart rmiregistry
35The Compute example
- At the heart of the compute engine is a protocol
that allows jobs to be submitted to the compute
engine, the compute engine to run those jobs, and
the results of the job to be returned to the
client. This protocol is expressed in interfaces
supported by the compute engine and by the
objects that are submitted to the compute engine,
as shown in the following figure. - Each of the interfaces contains a single method.
36About the example
- The return value for the Compute's executeTask
and Task's execute methods is declared to be of
type Object. This means that any task that wants
to return a value of one of the primitive types,
such as an int or a float, needs to create an
instance of the equivalent wrapper class for that
type, such as an Integer or a Float, and return
that object instead.
37About the example
- Note that the Task interface extends the
java.io.Serializable interface. RMI uses the
object serialization mechanism to transport
objects by value between Java virtual machines.
Implementing Serializable marks the class as
being capable of conversion into a
self-describing byte stream that can be used to
reconstruct an exact copy of the serialized
object when the object is read back from the
stream.
38About the example
- Different kinds of tasks can be run by a Compute
object as long as they are implementations of the
Task type. The classes that implement this
interface can contain any data needed for the
computation of the task and any other methods
needed for the computation.
39About the example
- Here is how RMI makes this simple compute engine
possible. - Since RMI can assume that the Task objects are
written in the Java programming language,
implementations of the Task object that were
previously unknown to the compute engine are
downloaded by RMI into the compute engine's
virtual machine as needed. - This allows clients of the compute engine to
define new kinds of tasks to be run on the server
machine without needing the code to be explicitly
installed on that machine. In addition, because
the executeTask method returns a
java.lang.Object, any type of object can be
passed as a return value in the remote call.
40About the example
- The compute engine, implemented by the
ComputeEngine class, implements the Compute
interface, allowing different tasks to be
submitted to it by calls to its executeTask
method. These tasks are run using the task's
implementation of the execute method. The compute
engine reports results to the caller through its
return value an Object.
41compute.Compute
- The compute.Compute interface defines the
remotely accessible part--the compute engine
itself. Here is the remote interface with its
single method - package compute
- import java.rmi.Remote
- import java.rmi.RemoteException
- public interface Compute extends Remote
- Object executeTask(Task t) throws
RemoteException - By extending the interface java.rmi.Remote, this
interface marks itself as one whose methods can
be called from any virtual machine. Any object
that implements this interface becomes a remote
object.
42compute.Task
- The compute.Task interface defines the interface
between the compute engine and the work that it
needs to do, providing the way to start the work.
- package compute
- import java.io.Serializable
- public interface Task extends Serializable
- Object execute()
- The Task interface defines a single method,
execute, which returns an Object, has no
parameters, and throws no exceptions. Since the
interface does not extend Remote, the method in
this interface doesn't need to list
43the implementation class of a remote interface
- general the implementation class of a remote
interface should at least - Declare the remote interfaces being implemented
- Define the constructor for the remote object
- Provide an implementation for each remote method
in the remote interfaces - The server needs to create and to install the
remote objects. This setup procedure can be
encapsulated in a main method in the remote
object implementation class itself, or it can be
included in another class entirely. The setup
procedure should - Create and install a security manager
- Create one or more instances of a remote object
- Register at least one of the remote objects with
the RMI remote object registry (or another naming
service such as one that uses JNDI), for
bootstrapping purposes
44The complete implementation of the compute engine
- The complete implementation of the compute engine
follows. The engine.ComputeEngine class
implements the remote interface Compute and also
includes the main method for setting up the
compute engine.
45ComputeEngine
- package engine
- import java.rmi.
- import java.rmi.server.
- import compute.
- public class ComputeEngine extends
UnicastRemoteObject implements Compute - public ComputeEngine() throws RemoteException
super() public Object executeTask(Task t)
return t.execute() - public static void main(String args)
- if (System.getSecurityManager() null)
System.setSecurityManager(new RMISecurityManager()
) - String name "//host/Compute"//change to
localhost - try Compute engine new ComputeEngine()
Naming.rebind(name, engine) System.out.println("C
omputeEngine bound") - catch (Exception e) System.err.println("ComputeE
ngine exception " e.getMessage())
e.printStackTrace()
46Client files class Pi implements Task, slide1
- package client
- import compute.
- import java.math.
- public class Pi implements Task
- / constants used in pi computation /
- private static final BigDecimal ZERO
- BigDecimal.valueOf(0)
- private static final BigDecimal ONE
- BigDecimal.valueOf(1)
- private static final BigDecimal FOUR
- BigDecimal.valueOf(4)
- / rounding mode to use during pi
computation / - private static final int roundingMode
- BigDecimal.ROUND_HALF_EVEN
- / digits of precision after the decimal
point / - private int digits
- /Construct a task to calculate pi to the
specified precision. / - public Pi(int digits)
- this.digits digits
47Client files class Pi implements Task, slide2
- / Calculate pi. /
- public Object execute()
- return computePi(digits)
-
- /
- Compute the value of pi to the specified
number of - digits after the decimal point. The value
is - computed using Machin's formula
- pi/4 4arctan(1/5) -
arctan(1/239) - and a power series expansion of arctan(x)
to - sufficient precision.
- /
- public static BigDecimal computePi(int
digits) - int scale digits 5
- BigDecimal arctan1_5 arctan(5, scale)
- BigDecimal arctan1_239 arctan(239,
scale) - BigDecimal pi arctan1_5.multiply(FOUR).s
ubtract( -
arctan1_239).multiply(FOUR)
48Client files class Pi implements Task, slide3
- public static BigDecimal arctan(int inverseX,
- int scale)
- BigDecimal result, numer, term
- BigDecimal invX BigDecimal.valueOf(inver
seX) - BigDecimal invX2
- BigDecimal.valueOf(inverseX
inverseX) - numer ONE.divide(invX, scale,
roundingMode) - result numer
- int i 1
- do
- numer
- numer.divide(invX2, scale,
roundingMode) - int denom 2 i 1
- term numer.divide(BigDecimal.valueO
f(denom), scale, roundingMode) - if ((i 2) ! 0) result
result.subtract(term) - else result result.add(term)
- i
- while (term.compareTo(ZERO) ! 0)
- return result
49Compute client files in client directory
ComputePi
- package client
- import java.rmi.
- import java.math.
- import compute.
- public class ComputePi
- public static void main(String args)
- if (System.getSecurityManager() null)
- System.setSecurityManager(new
RMISecurityManager()) - try
- String name "//" args0
"/Compute" - Compute comp (Compute)
Naming.lookup(name) - Pi task new Pi(Integer.parseInt(args
1)) - BigDecimal pi (BigDecimal)
(comp.executeTask(task)) - System.out.println(pi)
- catch (Exception e)
- System.err.println("ComputePi
exception " e.getMessage()) - e.printStackTrace()
-
50Rmiregistry (run) and run engine (server) I
used a batch file
- C\PROGRA1\JAVA\JDK151.0_0\BINgtrmiregistry
- c\PROGRA1\Java\JDK151.0_0\bingtjava
-Djava.security.policyjava.policy engin - e.ComputeEngine
- ComputeEngine bound
51Run client- you may want a batch file
- Client expects server name to be passed as well
as how many digits of pi are required. Output - C\PROGRA1\JAVA\JDK151.0_0\BINgtrunclient
- c\PROGRA1\Java\JDK151.0_0\bingtjava
-Djava.security.policyjava.policy - client.ComputePi localhost 20
- 3.14159265358979323846
52More remarks
- Youll need to change minor code in the engine
and client where it specifies the host url. I
used localhost.
53UnicastRemoteObject
- A remote object implementation does not have to
extend UnicastRemoteObject, but any
implementation that does not must supply
appropriate implementations of the
java.lang.Object methods. Furthermore, a remote
object implementation must make an explicit call
to one of UnicastRemoteObject's exportObject
methods to make the RMI runtime aware of the
remote object so that the object can accept
incoming calls. By extending UnicastRemoteObject,
the ComputeEngine class can be used to create a
simple remote object that supports unicast
(point-to-point) remote communication and that
uses RMI's default sockets-based transport for
communication.
54- If you choose to extend a remote object from any
class other than Unicast-RemoteObject or,
alternatively, extend from the new JDK 1.2 class
java.rmi.activation.Activatable (used to
construct remote objects that can execute on
demand), you need to export the remote object by
calling either the UnicastRemoteObject.exportObjec
t or Activatable.exportObject method explicitly
from your class's constructor (or another
initialization method, as appropriate).
55Define the Constructor
- The ComputeEngine class has a single constructor
that takes no arguments. - The code for the constructor is
- public ComputeEngine() throws RemoteException
super() - This constructor simply calls the superclass
constructor, which is the no-argument constructor
of the UnicastRemoteObject class. Although the
superclass constructor gets called even if
omitted from the ComputeEngine constructor, we
include it for clarity. During construction, a
UnicastRemoteObject is exported, meaning that it
is available to accept incoming requests by
listening for incoming calls from clients on an
anonymous port.
56Passing Objects in RMI
- Arguments to or return values from remote methods
can be of almost any type, including local
objects, remote objects, and primitive types.
More precisely, any entity of any type can be
passed to or from a remote method as long as the
entity is an instance of a type that is a
primitive data type, a remote object, or a
serializable object, which means that it
implements the interface java.io.Serializable. - A few object types do not meet any of these
criteria and thus cannot be passed to or returned
from a remote method. Most of these objects, such
as a file descriptor, encapsulate information
that makes sense only within a single address
space. Many of the core classes, including those
in the packages java.lang and java.util,
implement the Serializable interface.
57The rules governing how arguments and return
values are passed
- Remote objects are essentially passed by
reference. A remote object reference is a stub,
which is a client-side proxy that implements the
complete set of remote interfaces that the remote
object implements. - Local objects are passed by copy, using object
serialization. By default all fields are copied,
except those that are marked static or transient.
Default serialization behavior can be overridden
on a class-by-class basis. - Passing an object by reference (as is done with
remote objects) means that any changes made to
the state of the object by remote method calls
are reflected in the original remote object. When
passing a remote object, only those interfaces
that are remote interfaces are available to the
receiver any methods defined in the
implementation class or defined in nonremote
interfaces implemented by the class are not
available to that receiver.
58Implement the Server's main Method
- The most involved method of the ComputeEngine
implementation is the main method. The main
method is used to start the ComputeEngine and
therefore needs to do the necessary
initialization and housekeeping to prepare the
server for accepting calls from clients. This
method is not a remote method, which means that
it cannot be called from a different virtual
machine. Since the main method is declared
static, the method is not associated with an
object at all but rather with the class
ComputeEngine.
59Create and Install a Security Manager
- The first thing that the main method does is to
create and to install a security manager, which
protects access to system resources from
untrusted downloaded code running within the
virtual machine. The security manager determines
whether downloaded code has access to the local
file system or can perform any other privileged
operations. All programs using RMI must install a
security manager, or RMI will not download
classes (other than from the local class path)
for objects received as parameters, return
values, or exceptions in remote method calls.
This restriction ensures that the operations
performed by downloaded code go through a set of
security checks. - The ComputeEngine uses a security manager
supplied as part of the RMI system, the
RMISecurityManager. This security manager
enforces a similar security policy as the typical
security manager for applets that is to say, it
is very conservative as to what access it allows.
An RMI application could define and use another
SecurityManager class that gave more liberal
access to system resources or, in JDK 1.2, use a
policy file that grants more permissions.
60SecurityManager
- Here's the code that creates and installs the
security manager - if (System.getSecurityManager() null)
System.setSecurityManager(new RMISecurityManager()
)
61Build a JAR File of Interface Classes
- C\PROGRA1\JAVA\JDK151.0_0\BINgtCompute
- c\PROGRA1\Java\JDK151.0_0\bingtjavac
compute\Compute.java - c\PROGRA1\Java\JDK151.0_0\bingtjavac
compute\Task.java - c\PROGRA1\Java\JDK151.0_0\bingtjar cvf
compute.jar compute\.class - added manifest
- adding compute/Compute.class(in 238) (out
169)(deflated 28) - adding compute/Task.class(in 166) (out
138)(deflated 16)
62Server batch file
- C\PROGRA1\JAVA\JDK151.0_0\BINgtserver
- c\PROGRA1\Java\JDK151.0_0\bingtjavac
engine\ComputeEngine.java - c\PROGRA1\Java\JDK151.0_0\bingtrmic -d .
engine.ComputeEngine
63About the batch file
- The -d option tells the rmic compiler to place
the generated class files, ComputeEngine_Stub.clas
s and ComputeEngine_Skel.class, in the directory
c\home\ann\src\engine. You also need to make the
stubs and the skeletons network accessible, so
you must copy the stub and the skeleton class to
the area public_html\classes. - Since the ComputeEngine's stub implements the
Compute interface, which refers to the Task
interface, you need to make these two interface
class files network accessible along with the
stub. So the final step is to unpack the
compute.jar file in the directory
c\home\ann\public_html\classes to make the
Compute and the Task interfaces available for
downloading.
64unpack the compute.jar file in the directory
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjar xvf
compute.jar - created META-INF/
- inflated META-INF/MANIFEST.MF
- inflated compute/Compute.class
- inflated compute/Task.class
65Create client classes
- C\PROGRA1\JAVA\JDK151.0_0\BINgtclient.bat
- c\PROGRA1\Java\JDK151.0_0\bingtjavac
client\ComputePi.java - c\PROGRA1\Java\JDK151.0_0\bingtjavac
client\Pi.java
66distribute the compute.jar file to developers of
server and client applications so that they can
make use of the interfaces.
- When you build either server- or client-side
classes with the javac and rmic compilers, you
generally need to specify where the resulting
class files should reside so that they are
network accessible. In this example this location
is, for UNIX, /home/user/public_html/classes,
because some web servers allow accessing a user's
public_html directory via an HTTP URL constructed
as http//host/user/. If your web server does
not support this convention, you could use a file
URL instead. The file URLs take the form
file/home/user/public_html/classes/ on UNIX or,
on the Microsoft Windows platform,
file/c/home/user/public_html/classes/. You may
also select another type of URL, as appropriate. - The network accessibility of the class files
allows the RMI runtime to download code when
needed. Rather than defining its own protocol for
code downloading, RMI uses URL protocols
supported by the Java platform (for example,
HTTP) to download code. Note that a full,
heavyweight web server is not needed to
accomplish this downloading of class files. In
fact, a simple HTTP server that provides all of
the functionality needed to make classes
available for downloading in RMI via HTTP can be
found at ftp//ftp.javasoft.com/pub/jdk1.1/rmi/cla
ss-server.zip.
67Build the Server Classes
- The engine package contains only one server-side
implementation class, ComputeEngine, the remote
object implementation of the Compute interface.
Since ComputeEngine is an implementation of a
remote interface, you need to generate a stub for
the remote object so that clients can contact the
remote object. Let's say that ann, the developer
of the ComputeEngine class, has placed
ComputeEngine.java in the c\home\ann\src\engine
directory and is deploying the class files for
clients to use in a subdirectory of her
public_html directory, c\home\ann\public_html\cla
sses (on UNIX that would be /home/ann/public_html/
classes, accessible via some web servers as
http//host/ann/classes/). - Now let's assume that the compute.jar file is
located in the directory c\home\ann\public_html\c
lasses. To compile the ComputeEngine class, your
class path must include the compute.jar file and
the source directory itself.
68RMI with a form for client which calls a client
servlet to access a remote method
69Html to access servlet
- ltHTMLgt
- ltBODYgt
- ltH1gtRMI AND SERVLETSlt/H1gt
- ltFORM METHOD"get"
- action "http//localhost8080/rmi/ClientServlet"gt
- ltINPUT TYPE"Text" name"username"gt
- ltINPUT TYPE"submit" value"Click me"gt
- lt/FORMgt
- lt/BODYgt lt/HTMLgt
70Client servlet accesses remote method
71The files ClientServlet
- import javax.servlet.
- import javax.servlet.http.
- import java.io. import java.rmi.
- //client implementation
- public class ClientServlet extends HttpServlet
- //reference to the remote server
- private ServerHandlerInterface obj
- //Initialize the servlet and log the
initialization. - public void init(ServletConfig c) throws
ServletException super.init(c) - try
- //get a remote reference
- obj (ServerHandlerInterface)Naming.lookup("Serve
r") - catch(Exception ex)
- System.out.println("Error "
ex.getMessage()) - //Perform the HTTP GET operation
- public void doGet(HttpServletRequest
req,HttpServletResponse res) throws
ServletException,IOException - //get the name of the user
- String name req.getParameter("username")
- String result null
72ServerHandlerImpl (need to do both javac and rmic)
- import java.rmi.
- import java.rmi.server.
- import java.rmi.registry.
- // server class
- public class ServerHandlerImpl extends
UnicastRemoteObject implements
ServerHandlerInterface - //constructor
- public ServerHandlerImpl() throws
RemoteException System.out.println("Creating
server object") - //remote method called by the servlet
- public String servletTest(String name) throws
RemoteException - String res "Your name is "name"\n" "\n\n
Returned by RMI Server" return res - //main method creates an instance of the remote
object - //and binds it with the registry service
- public static void main(String args)
-
- try
- ServerHandlerImpl obj new ServerHandlerImpl()
- Registry reg LocateRegistry.createRegistry(1099)
- reg.rebind("Server",obj) catch(Exception ex)
- System.out.println(ex.getMessage()) //catch
73Remote method interface file
- import java.rmi.
- public interface ServerHandlerInterface extends
Remote - public String servletTest(String name) throws
RemoteException
74You need to run this application note path
- C\PROGRA1\TOMCAT1.5\WEBAPPS\RMI\WEB-INF\CLASSES
gtjava ServerHandlerImpl - Creating server object
75remarks
- Need to add the servlet and mapping to web.xml
- Need to put stub and class files for the three
java classes into your web app. - Need to run the application over in the webapp
directory--- seems like a tedious superfluity so
wed like an example without this.
76Generalizing the example to route requests
choose one method
77Or another
78The classes Router servlet
- import javax.servlet.
- import javax.servlet.http.
- import java.io. import java.rmi.
- //client implementation
- public class RouterServlet extends HttpServlet
- //reference to the remote server
- private GeneralizedServerInterface obj1,obj2
- //Initialize the servlet and log the
initialization. - public void init(ServletConfig c) throws
ServletException super.init(c) - try
- //get a remote reference
- obj1 (GeneralizedServerInterface)Naming.lookup("
Name") - obj2 (GeneralizedServerInterface)Naming.lookup("
Number") - catch(Exception ex)
- System.out.println("Error "
ex.getMessage()) - //Perform the HTTP GET operation
- public void doGet(HttpServletRequest
req,HttpServletResponse res) throws
ServletException,IOException - //get the name of the user
- String name req.getParameter("methodname")
79Implementation (needs class file but also stub
file from rmic in classes directory)
- import java.rmi.
- import java.rmi.server.
- import java.rmi.registry.
- // a server class...provides various methods
- public class GeneralizedServerImpl extends
UnicastRemoteObject implements
GeneralizedServerInterface - //constructor
- public GeneralizedServerImpl() throws
RemoteException System.out.println("Creating
server object") - //remote method called by the servlet
- public String servletTest(String name) throws
RemoteException - String res "Your name is "name"\n" "\n\n
Returned by RMI Server" return res - //main method creates an instance of the remote
object - //and binds it with the registry service
- public int valueTest(int num) throws
RemoteException - int resnum10return res
- public static void main(String args)
- try
- GeneralizedServerImpl obj1 new
GeneralizedServerImpl() - GeneralizedServerImpl obj2 new
GeneralizedServerImpl() - Registry reg LocateRegistry.createRegistry(1099)
80A list of services might appear in the remote
interface file
- import java.rmi.
- //maybe a whole list of services?
- public interface GeneralizedServerInterface
extends Remote - public String servletTest(String name) throws
RemoteException - public int valueTest(int num) throws
RemoteException
81remarks
- The GeneralizedServerImpl file is compiled using
javac, then the class file is complied using
rmic. Both output files (class and stub.class) go
in classes directory of webapps - Using this rmi model we need to run the
application impl which logs the methods into a
registry - C\PROGRA1\TOMCAT1.5\WEBAPPS\RMI\WEB-INF\CLASSES
gtjava GeneralizedServerImpl - Creating server object
- Creating server object
82A process can use registry.list() to see bound
remote interfaces
83RemoteHttpServlet binds servlet to registry
- try
- registry.rebind(getRegistryName(),this)
- catch()
84Some links for tutorials and examples
- http//java.sun.com/developer/JDCTechTips/2001/tt0
227.html - http//java.sun.com/developer/onlineTraining/rmi/R
MI.html - http//www.javacommerce.com/displaypage.jsp?names
ecurity.sqlid18224
85Tunneling
- Tunneling can be used to access RMI through a
firewall. The client connects (requests a
service) via http to a remote server and a
servlet routes the client to the running rmi
server. - The servlet must have mapping to
- /cgi-bin/java-rmi.cgi
86SUN java web server
87Requires creating war file
- http//www.hccfl.edu/pollock/AJava/WAR/myServletWA
R.htm - C\PROGRA1\JAVA\JDK151.0_0\BIN\TMP\SESSIONgtC\PR
OGRA1\JAVA\JDK151.0_0\BIN\jar -cvf session.war
. - added manifest
- adding WEB_INF/(in 0) (out 0)(stored 0)
- adding WEB_INF/classes/(in 0) (out 0)(stored
0) - adding WEB_INF/classes/SessionInfo.class(in
1926) (out 1051)(deflated 45) - adding WEB_INF/classes/SessionSnoop.class(in
3446) (out 1755)(deflated 49) - adding WEB_INF/web.xml(in 1002) (out
332)(deflated 66)
88Deploy a webapp (war)
89Editing webapps in sun web server
90Configuring tomcat to listen at port 80
- You can configure tomcat to listen at port 80
instead of port 8080 - The file tomacat\conf\server.xml controls the
port where tomcat listensline 77 in my tomcat
5.5 container - lt!-- Define a non-SSL HTTP/1.1 Connector on port
8080 modified to read port 80 11/28/06--gt - ltConnector port"80" maxHttpHeaderSize"8192"
91Tunneling
- Tunneling is not a trick but is specifically
provided for by RMI which automatically tries
this avenue if other efforts to locate the method
fail. - To force tunneling for development purposes
when there is no firewall you add a couple of
lines to your client - try
- RMISocketFactory.setSocketFactory(new
sun.rmi.transport.proxy.RMIHttpToCGISocketFactory(
)) -
- Catch(IOException x)
92Converting ANY rmi client/server into a tunneler
- No change needed to the server.
- Youll need to put the Impl and Impl_Stub class
files in the classes directory of ROOT/WEB-INF - Remember, the stub file is created by using the
rmi compiler on the impl class file. - Youll need to get the tunneler servlet files off
the network, or from me, and deploy into
Tomcat/webapps/Root with mapping as above
(/cgi-bin/)
93Example Hello client and servermodified client
- import java.rmi.
- import java.rmi.server.//////note additional
imports - import java.io.
- import java.rmi.registry.LocateRegistry
- import java.rmi.registry.Registry
- public class HelloClient2
- private HelloClient2()
- public static void main(String args)
- String host (args.length lt 1) ? null
args0 - try /////note this addition
- RMISocketFactory.setSocketFactory(new
sun.rmi.transport.proxy.RMIHttpToCGISocketFactory(
)) - Registry registry LocateRegistry.getRegistr
y(host) - Hello stub (Hello) registry.lookup("HelloSe
rver") - String response stub.sayHello()
- System.out.println("response " response)
- catch (Exception e)
- System.err.println("Client exception "
e.toString()) - e.printStackTrace()
94Get the server running
- You might want to use a policy file and a batch
file - Heres a java.policy file
- grant
- permission java.security.AllPermission
- permission java.net.SocketPermission
"localhost1024-", "connect,listen,accept,resolve"
-
95Get the server running
- Put the impl and impl stub files in
ROOT/WEB-INF/classes - Make sure youve got that tunneler servlet
working - Startup tomcat
- Startup rmi registry
- Run the server
96Batch file for server run client
- java -Djava.security.manager -Djava.security.polic
y"java.policy" HelloImpl - Note--- in my version I bind HelloServer to the
registry, not Hello so I modified the client to
look for this - Output
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
HelloClient2 - response Hello World!
97A second tunneling example
- The calculator example from above can be easily
modified to go through http
98Calculator modified to go through rmi tunneling
output
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
CalculatorClient2 - 1
- 9
- 18
- 3
99CalcClient2 forced to go through http tunnel
- import java.net.MalformedURLException
- import java.rmi.
- import java.rmi.server.
- import java.io.
- public class CalculatorClient2
- public static void main(String args)
- try RMISocketFactory.setSocketFactory(ne
w sun.rmi.transport.proxy.RMIHttpToCGISocketFactor
y()) - Calculator c (Calculator)
Naming.lookup("CalculatorService") - System.out.println( c.sub(4, 3) )
- System.out.println( c.add(4, 5) )
- System.out.println( c.mul(3, 6) )
- System.out.println( c.div(9, 3) )
- catch (MalformedURLException murle)
- System.out.println()
- System.out.println(
- "MalformedURLException")
- System.out.println(murle)
-
100And more catches
- catch (RemoteException re)
- System.out.println()
- System.out.println("RemoteException")
- System.out.println(re)
-
- catch (IOException io)
- System.out.println()
- System.out.println(
"IOException") - System.out.println(io.toString())
- catch (NotBoundException nbe)
- System.out.println()
- System.out.println("NotBoundException"
) - System.out.println(nbe)
-
- catch (
- java.lang.ArithmeticException ae)
- System.out.println()
- System.out.println("java.lang.Arithmet
icException") - System.out.println(ae)
101No changes to calculator server
- Need to move copy of impl and stub files to your
server classes directory.
102I added print statements to my cgi servlet
forwarder
103Third example from Grossos RMI text, chapter
22.It is much more involved than the previous two
- You can get the code off the internet look for
Grosso RMI text
104rmic_bankserver.bat and bankserver.bat
- May need to edit the batch files to get rmic and
start registry to work. - I removed these lines from the batch files and
performed them in a different directory.
105Starting registry and creating stub files via rmic
- c\PROGRA1\Java\JDK151.0_0\bingtrmic
com.ora.rmibook.chapter22.Account_Impl - C\PROGRA1\JAVA\JDK151.0_0\BINgtstart
rmiregistry - C\PROGRA1\JAVA\JDK151.0_0\BINgt
106Running the bankserver
- c\PROGRA1\java\JDK151.0_0\bin\com\ora\rmibook\C
HAPTE1gtjava -Djava.security.m - anager -Djava.security.policy"java.policy"
com.ora.rmibook.chapter22.applicatio - ns.ImplLauncher Bob 10000 Alex 1223
- Account Bob successfully launched.
- Account Alex successfully launched.
107java.policy file
- grant
- permission java.security.AllPermission
- permission java.net.SocketPermission
"localhost1024-", "connect,listen,accept,resolve"
-
108Tunneling problems
- The rmi client goes makes a request for a servlet
on port 80 (not port 8080) - Youll need to modify the server.xml in conf
directory of tomcat, or use another container. - I installed the sun webserver on my machine. It
listens on port 80 and servlet deployment is
fairly simple. (Though I never got it working)
109Tunneler Running
110I had to make some changes
- It doesnt completely work
- There is some error - possibly in the text code
(to write objects)
111The servlet and exception and other java files
are in higgindm/internet prgramming/java/tunneler
112modifications
- I removed the package code though it probably
wasnt necessary