Run the client
Step 1:
Compile the remote interface, implementation, client
and setup classes
% javac -d . AnotherRemoteInterface.java
% javac -d . MyClass.java
% javac -d . Client3.java
% javac -d . Setup3.java
Step 2:
Run rmic
on the implementation class
% rmic -d . examples.activation.MyClass
Step 3:
Start the rmiregistry
% rmiregistry &
Note: Before you start
the rmiregistry, you must make sure that the shell or window in which
you will run the registry
, either has no CLASSPATH
set or has a CLASSPATH that does not include the path to any classes
that you want downloaded to your client, including the stubs for your
remote object implementation classes.
If you start the rmiregistry
, and it
can find your stub classes in its CLASSPATH, it will ignore the
server's java.rmi.server.codebase
property, and as
a result, your client(s) will not be able to download the stub code for
your remote object.
Step 4:
Start the activation daemon, rmid
% rmid -J-Djava.security.policy=rmid.policy &
Where rmid.policy
is the name of the security policy file for rmid
.
Note: By default, rmid
now requires a security
policy file, that is used to verify whether or not the information in
each ActivationGroupDescriptor
is allowed to be used to
launch a JVM for an activation group. For complete details, please
refer to the rmid
man
page for the Solaris operating environment and the rmid
man
page for the Microsoft Windows platform.
Step 5:
Run the setup program
Run the setup, setting the codebase property to be the location of
the implementation stubs. There are four things that need to go on the
same command line:
- The "
java
" command
- A property name=value pair that specifies the
location of the security policy file
- A property to specify where the stub code lives (no spaces
from the "-D" all the way though the last "/")
- The fully-qualified package name of the setup program.
There should be one space just after the word "java
",
one between the two properties, and a third one just before the word
"examples
" (which is very hard to see when you view this
as text, in a browser, or on paper).
% java -Djava.security.policy=/home/rmi_tutorial/activation/policy
-Djava.rmi.server.codebase=file:/home/rmi_tutorial/activation/ examples.activation.Setup3
The codebase property will be resolved to a URL, so it must have the
form of "http://aHost/somesource/
" or
"file:/myDirectory/location/
" or, due to the requirements
of some operating systems, "file:///myDirectory/location
/"
(three slashes after the "file:
").
While a file:
URL is sometimes easier to use for
running example code, using the file:
URL will mean that
the only clients that will be able to access the server are those that
can access the same files system as the server (either by virtue of
running on the same machine as the server or by using a shared
filesystem, such as NFS). If you wish to use an HTTP server, but don't
have one available to you, please feel free to download
our HTTP server.
Please note that each of these sample URL strings has a trailing
"/". The trailing slash is a requirement for the URL set by the
java.rmi.server.codebase
property, so the implementation
can resolve (find) your class definition(s) properly. For more
information on setting the java.rmi.server.codebase
property from the command line, please take a look at our tutorial on
dynamic code downloading using the
java.rmi.server.codebase
property.
If you forget the trailing slash on the property, or if the class
files can't be located at the source (they aren't really being made
available for download) or if you misspell the property name, you'll
get thrown a java.lang.ClassNotFoundException.
This
exception will be thrown when you try to bind your remote object to the
rmiregistry
, or when the first client attempts to access
that object's stub. If the latter case occurs, you have another problem
as well because the rmiregistry
was finding the stubs in its CLASSPATH.
The server output should look like this:
Got the stub for MyClass
Exported MyClass
Step 6:
Run the client
The argument to the client program is the hostname of the
implementation server, in this case, "vector
".
% java -Djava.security.policy=/home/rmi_tutorial/activation/policy
examples.activation.Client3 vector
The client output should look like this:
Got a remote reference to the class MyClass
Called the remote method
Result: Watson are you there? I'm here!
An Alternate Approach
An alternative approach to what we just went through is to create an
"adapter" class that implements the remote interface, gets registered
with rmid
and the registry by the setup program, and which
then creates the object instance and forwards the remote method to that
instance. The benefit to this approach is that you don't have to make a
change to the original non-remote class.
So, let's assume that the original, non-remote class, looks like
this:
package examples.activation;
public class MyNonRemoteClass {
private String result = null;
// Here's the original class, which concatenates two strings
//
public String calltheServer(String takeThis) {
result = takeThis + "I'm here!";
return result;
}
}
We write the same interface,
examples.activation.AnotherRemoteInterface
, to describe
the methods we'd like to call remotely:
package examples.activation;
import java.rmi.*;
public interface AnotherRemoteInterface extends Remote {
public String calltheServer(String s) throws RemoteException;
}
But rather than editing MyNonRemoteClass.java
, which we
may not always have the source code to do anyway, we'll create a new
class
examples.activation.MyNonRemoteClassAdapter
, which (like an
event adapter) implements the specified interface, and then takes
appropriate action. What's new in MyNonRemoteClassAdapter
from what we did earlier, is that it creates an instance of
MyNonRemoteClass
in it's constructor and it calls the
MyNonRemoteClass.calltheServer
method.
package examples.activation;
import java.rmi.*;
import java.rmi.activation.*;
public class MyNonRemoteClassAdapter implements
examples.activation.AnotherRemoteInterface
{
private String result = null;
private MyNonRemoteClass mnrc;
// The constructor for activation and export; this
// constructor is called by the method
// ActivationInstantiator.newInstance during
// activation, to construct the object.
//
public MyNonRemoteClassAdapter(ActivationID id,
MarshalledObject data) throws RemoteException
{
// Register the object with the activation system
// then export it on an anonymous port
//
Activatable.exportObject(this, id, 0);
// Create an instance of the class MyNonRemoteClass
//
mnrc = new MyNonRemoteClass();
}
// Define the method declared in AnotherRemoteInterface
// to accept a String, modify it, and return it to
// the client
//
public String calltheServer(String takeThis)
throws RemoteException
{
// Rather than modify the String here, forward
// it on to the non-remote object implementation
//
result = mnrc.calltheServer(takeThis);
return result;
}
}
Now the class we'll run rmic
on and the class
referenced by the setup program will be the adapter class. The setup
program examples.activation.Setup3alt
looks like this now:
package examples.activation;
import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;
public class Setup3alt {
// This class registers information about the MyClass
// class with rmid and the rmiregistry
//
public static void main(String[] args) throws Exception {
System.setSecurityManager(new RMISecurityManager());
AnotherRemoteInterface ari;
// Don't forget the trailing slash at the end of the URL
// or your classes won't be found
//
String location = "file:/home/rmi_tutorial/activation/";
// Create the rest of the parameters that will be passed to
// the ActivationDesc constructor
//
MarshalledObject data = null;
// The second argument to the ActivationDesc constructor
// will be used to uniquely identify this class; it's
// location is relative to theURL-formatted String, location.
//
ActivationDesc desc = new ActivationDesc
("examples.activation.MyNonRemoteClassAdapter",
location, data);
ari = (AnotherRemoteInterface)Activatable.register(desc);
System.out.println("Got the stub for MyNonRemoteClassAdapter");
// Bind the stub to a name in the registry running on 1099
//
Naming.rebind("MyNonRemoteClassAdapter", ari);
System.out.println("Exported MyNonRemoteClassAdapter");
System.exit(0);
}
}
*As used on this web site, the terms "Java virtual machine" or "JVM"
mean a virtual machine for the Java platform.