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.
4Java Remote Object Invocation (RMI)
- Overview of RMI
- Java RMI allows programmer to execute remote
function class using the same semantics as local
functions calls.
5The General RMI Architecture
- The server must first bind its name to the
registry - The client looks up the server name in the
registry to establish remote references. - The Stub serializes the parameters to the
skeleton, the skeleton invokes the remote method
and seriales the result back to the stub.
6The Stub and Skeleton
- A client invokes a remote method, the call is
first forwarded to stub. - The stub is responsible for sending the remote
call over to the server-side skeleton - The stub opening a socket to the remote server,
marshaling the object parameters and forwarding
the data stream to the skeleton. - A skeleton contains a method that receives the
remote calls, unmarshals the parameters, and
invokes the actual remote object implementation.
7Steps for Developing an RMI System
- 1. Define the remote interface
- 2. Develop the remote object by implementing the
remote interface. - 3. Develop the client program.
- 4. Compile the Java source files.
- 5. Generate the client stubs and server
skeletons. - 6. Start the RMI registry.
- 7. Start the remote server objects.
- 8. Run the client
8Step 1 Defining the Remote Interface
- To create an RMI application, the first step is
the defining of a remote interface between the
client and server objects. - / SampleServer.java /
- import java.rmi.
- public interface SampleServer extends Remote
-
- public int sum(int a,int b) throws
RemoteException -
9Step 2 Develop the remote object and its
interface
- The server is a simple unicast remote server.
- Create server by extending java.rmi.server.Unicast
RemoteObject. - The server uses the RMISecurityManager to protect
its resources while engaging in remote
communication. - / SampleServerImpl.java /
- import java.rmi.
- import java.rmi.server.
- import java.rmi.registry.
- public class SampleServerImpl extends
UnicastRemoteObject - implements
SampleServer -
- SampleServerImpl() throws RemoteException
-
- super()
-
10Step 2 Develop the remote object and its
interface
- Implement the remote methods
- / SampleServerImpl.java /
- public int sum(int a,int b) throws
RemoteException -
- return a b
-
-
- The server must bind its name to the registry,
the client will look up the server name. - Use java.rmi.Naming class to bind the server name
to registry. In this example the name call
SAMPLE-SERVER. - In the main method of your server object, the RMI
security manager is created and installed.
11Step 2 Develop the remote object and its
interface
- / SampleServerImpl.java /
- public static void main(String args)
-
- try
-
- System.setSecurityManager(new
RMISecurityManager()) - //set the security manager
- //create a local instance of the object
- SampleServerImpl Server new
SampleServerImpl() - //put the local instance in the registry
- Naming.rebind("SAMPLE-SERVER" , Server)
- System.out.println("Server
waiting.....") -
- catch (java.net.MalformedURLException me)
- System.out.println("Malformed URL "
me.toString()) - catch (RemoteException re)
12Step 3 Develop the client program
- In order for the client object to invoke methods
on the server, it must first look up the name of
server in the registry. You use the
java.rmi.Naming class to lookup the server name. - The server name is specified as URL in the from
( rmi//hostport/name ) - Default RMI port is 1099.
- The name specified in the URL must exactly match
the name that the server has bound to the
registry. In this example, the name is
SAMPLE-SERVER - The remote method invocation is programmed using
the remote interface name (remoteObject) as
prefix and the remote method name (sum) as suffix.
13Step 3 Develop the client program
- import java.rmi.
- import java.rmi.server.
- public class SampleClient
-
- public static void main(String args)
-
- // set the security manager for the client
- System.setSecurityManager(new
RMISecurityManager()) - //get the remote object from the registry
- try
-
- System.out.println("Security Manager
loaded") - String url "//localhost/SAMPLE-SERVER"
- SampleServer remoteObject
(SampleServer)Naming.lookup(url) - System.out.println("Got remote
object") - System.out.println(" 1 2 "
remoteObject.sum(1,2) ) -
- catch (RemoteException exc)
- System.out.println("Error in lookup "
exc.toString())
14Step 4 5 Compile the Java source files
Generate the client stubs and server skeletons
- Assume the program needs to compile and execute
at home - Once the interface is completed, you need to
generate stubs and skeleton code. The RMI system
provides an RMI compiler (rmic) that takes your
generated interface class and procedures stub
code on its self. - promptgt set CLASSPATHhome
- promptgt javac SampleServer.java
- promptgt javac SampleServerImpl.java
- promptgt rmic SampleServerImpl
- promptgt javac SampleClient.java
15A 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.
16Windows 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.
17Windows 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
18Step 6 Start the RMI registry in its own command
window
- Open an extra command window
- The RMI applications need install in the
Registry. And the Registry must be started
manually by calling rmiregisty. - The rmiregistry uses port 1099 by default. You
can also bind rmiregistry to a different port by
indicating the new port number as rmiregistry
ltnew portgt -
- On Windows, you have to type on the command line
- gt start rmiregistry
19Port for rmi
- To run registry on Windows platforms
- Promptgtstart 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 - Promptgtstart rmiregistry 2001
-
20Steps 7 8 Start the remote server objects
Run the client
- Once the Registry is started, the server can be
started and will be able to store itself in the
Registry. - Because of the grained security model in Java
2.0, you must set up a security policy for RMI by
set java.security.policy to a file, for example,
policy.all - promptgt java Djava.security.policypolicy.all
SampleServerImpl - promptgt java Djava.security.policypolicy.all
SampleClient
21Java Policy File
- In Java 2, the java application must first obtain
information regarding its privileges. It can
obtain the security policy through a policy file.
If, in above example, we allow the Java code to
have all permissions, the contents of the policy
file policy.all would be - grant
- permission java.security.AllPermission
-
- Now, we given an example for assigning resource
permissions - grant
- permission java.io.filePermission /tmp/,
read, write - permission java.net.SocketPermission
somehost.somedomain.com999,connect - permission java.net.SocketPermission
1024-65535,connect,request - permission java.net.SocketPermission
80,connect -
22Comment for the Java Policy File
- 1. allow the Java code to read/write any files
only under the /tmp directory, includes any
subdirectories - 2. allow all java classes to establish a network
connection with the host somehost.somedomain.com
on port 999 - 3. allows classes to connection to or accept
connections on unprivileged ports greater than
1024 , on any host - 4. allows all classes to connect to the HTTP
port 80 on any host. - You can obtain complete details by following
links - http//java.sun.com/products//jdk/1.2/docs/guide/s
ecurity/spec/security-spec.doc3.html
23First 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
24Hello interface(extends remote)
- package example.hello
- import java.rmi.Remote
- import java.rmi.RemoteException
- public interface Hello extends Remote
- String sayHello() throws RemoteException
-
25Client
- 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()
-
-
-
26The 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())
27Compile 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!
28Dont forget to run rmic on the interface
- C\rmi_hello_worldgtrmic Hello
- C\rmi_hello_worldgtjava HelloServer
- Hello Server is ready.
- C\rmi_hello_worldgtjava HelloClient
- Hello, world!
29Same 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()
30The 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"
31Run 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
- (you get this message when it is bound)
32Hello 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.
33RMI
- 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 Firefox 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
34The tutorial url for this example
- http//java.sun.com/j2se/1.3/docs/guide/rmi/getsta
rt.doc.html5238
35Run the applet (the little hello world is the
message)
36The 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
-
37The calculator project implementation class
CalculatorImpl
- 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
-
- public long mul(long a, long b)
- throws java.rmi.RemoteException
- return a b
38The 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
39The 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()
-
40Calculator 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)
41Running 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 - gtrmiregistry
- If all goes well, the registry will start running
and you can switch to the next console. - In the second console. To start the server
hosting the CalculatorService 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.
42Screenshot of calculator
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
CalculatorClient - 1
- 9
- 18
- 3
- C\PROGRA1\JAVA\JDK151.0_0\BINgt
43A note
- This simple example is redone at the end using
the simplifiedservlethandler and
loggingservletforwarder implementing rmi through
http tunneling
44Computing somethinglike pi
- http//java.sun.com/docs/books/tutorial/rmi/overvi
ew.html
45Compiling 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)
46Jar 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
47Compile 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
48The 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.
49About 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.
50About 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.
51About 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.
52About 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.
53About 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.
54compute.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.
55compute.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
56the 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
57The 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.
58ComputeEngine
- 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()
59Client 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
60Client 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)
61Client 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
62Compute 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()
-
63Rmiregistry (run) and run engine (server) I
used a batch file
- gtrmiregistry
- gtjava -Djava.security.policyjava.policy
engine.ComputeEngine - ComputeEngine bound
64Run 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
65More remarks
- Youll need to change minor code in the engine
and client where it specifies the host url. I
used localhost.
66UnicastRemoteObject
- 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.
67- 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).
68Define 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.
69Passing 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.
70The 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.
71Implement 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.
72Create 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.
73SecurityManager
- Here's the code that creates and installs the
security manager - if (System.getSecurityManager() null)
System.setSecurityManager(new RMISecurityManager()
)
74Build 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)
75Server 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
76About 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.
77unpack 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
78Create 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
79distribute 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.
80Build 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.
81RMI with a form for client which calls a client
servlet to access a remote method
82Html 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
83Client servlet accesses remote method
84The 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
85ServerHandlerImpl (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
86Remote method interface file
- import java.rmi.
- public interface ServerHandlerInterface extends
Remote - public String servletTest(String name) throws
RemoteException
87You need to run this application note path
- C\PROGRA1\TOMCAT1.5\WEBAPPS\RMI\WEB-INF\CLASSES
gtjava ServerHandlerImpl - Creating server object
88remarks
- 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.
89Generalizing the example to route requests
choose one method
90Or another
91The 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")
92Implementation (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)
93A 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
94remarks
- The GeneralizedServerImpl file is compiled using
javac, then the class file is compiled 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
95A process can use registry.list() to see bound
remote interfaces
96RemoteHttpServlet binds servlet to registry
- try
- registry.rebind(getRegistryName(),this)
- catch()
97Some 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
98Tunneling
- 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
99SUN java web server
100Requires 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)
101Deploy a webapp (war)
102Editing webapps in sun web server
103Configuring tomcat to listen at port 80
- You can configure tomcat to listen at port 80
instead of port 8080 - The file tomcat\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"
104Tunneling
- 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)
105Converting 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/) I think its at http//java.sun.com/
j2se/1.3/docs/guide/rmi/archives/rmiservlethandler
.zip - The unzipped contents also has a readme with some
explanation.
106Example 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()
107Get 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"
-
108Get 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
109Batch 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!
110A second tunneling example
- The calculator example from above can be easily
modified to go through http
111Calculator modified to go through rmi tunneling
output
- C\PROGRA1\JAVA\JDK151.0_0\BINgtjava
CalculatorClient2 - 1
- 9
- 18
- 3
112CalcClient2 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)
-
113And 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)
114No changes to calculator server
- Need to move copy of impl and stub files to your
server classes directory.
115I added print statements to my cgi servlet
forwarder
116Related (RMI) project
- Maybe not too hard after all.
- Make changes to the task/compute (PI) RMI example
to effect RMI tunneling.
117Third 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
118rmic_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.
119Starting 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
120Running 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.
121java.policy file
- grant
- permission java.security.AllPermission
- permission java.net.SocketPermission
"localhost1024-", "connect,listen,accept,resolve"
-
122Tunneling 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)
123Tunneler Running
124I had to make some changes
- It doesnt completely work
- There is some error - possibly in the text code
(to write objects)
125The servlet and exception and other java files
are in higgindm/internet programming/java/tunneler
/.java
126modifications
- I removed the package code though it probably
wasnt necessary
127Tunneling with tomcat
- Background Tunneling
- Remote Method Invocation (RMI) in Java gives a
clean way to build distributed applications in
java. If you are on an Intranet with no
firewalls, RMI just works. But on the Internet,
where firewalls abound, RMI can be blocked
because it tries to connect to server hosts using
arbitrary port numbers. Typical firewalls on the
server side don't allow this. To alleviate this
problem, Sun built in to the RMI implementation a