|
[ <<BACK] [ CONTENTS] [ NEXT>>]
The Java Remote Method Invocation (RMI) application programming interface (API) enables client and server communications over the net. Typically, client programs send requests to a server program, and the server program responds to those requests.
A common example is sharing a word processing program over a network. The word processor is installed on a server, and anyone who wants to use it starts it from his or her machine by double clicking an icon on the desktop or typing at the command line. The invocation sends a request to a server program for acess to the software, and the server program responds by making the software available to the requestor.
The RMI API lets you create a publicly accessible remote server object that enables client and server communications through simple method calls on the server object. Clients can easily communicate directly with the server object and indirectly with each other through the server object using Uniform Resource Locators (URLs) and HyperText Transfer Protocol (HTTP).
This lesson explains how to use the RMI API to establish client and server communications.
| |
About the Example
This lesson converts the File Input and Output application from Lesson 6: File Access and Permissions to the RMI API.
Program Behavior
The
RMIClient1 program presents a simple user interface and prompts for text input. When you click the
Click Me button, the text is sent to the
RMIClient2 program by way of the remote server object. When you click the
Click Me button on the
RMIClient2 program, the text sent from
RMIClient1 appears.
If you start a second instance of
RMIClient1 and type in some text, that text is sent to
RMIClient2 when you click the
Click Me button. To see the text received by
RMIClient2, click its
Click Me button.
File Summary
The example program consists of the RMIClient1 program, remote object and interface, and the RMIClient2 program as illustrated in the diagram. The corresponding source code files for these executables are described in the bullet list below.
sendData method on the
RemoteServer server object.
getData method on the
RemoteServer server object.
Send.java and the
sendData and
getData remote methods.
sendData and
getData remote server methods.
In addition, the following java.policy security policy file grants the permissions needed to run the example.
grant {
permission java.net.SocketPermission
"*:1024-65535",
"connect,accept,resolve";
permission java.net.SocketPermission
"*:80", "connect";
permission java.awt.AWTPermission
"accessEventQueue";
permission java.awt.AWTPermission
"showWindowWithoutWarningBanner";
};
|
Compile the Example
These instructions assume development is in the
zelda home directory. The server program is compiled in the home directory for user
zelda, but copied to the
public_html directory for user
zelda where it runs.
Here is the command sequence for the Unix and Win32 platforms; an explanation follows.
Unix:
cd /home/zelda/classes
javac Send.java
javac RemoteServer.java
javac RMIClient2.java
javac RMIClient1.java
rmic -d . RemoteServer
cp RemoteServer*.class /home/zelda/public_html/classes
cp Send.class /home/zelda/public_html/classes
Win32:
cd \home\zelda\classes
javac Send.java
javac RemoteServer.java
javac RMIClient2.java
javac RMIClient1.java
rmic -d . RemoteServer
copy RemoteServer*.class \home\zelda\public_html\classes
copy Send.class \home\zelda\public_html\classes
|
The first two
javac commands compile the
RemoteServer and
Send class and interface. The third
javac command compiles the
RMIClient2 class. The last
javac command compiles the
RMIClient1 class.
The next line runs the
rmic command on the
RemoteServer server class. This command produces output class files of the form
ClassName_Stub.class and
ClassName_Skel.class. These output classes let clients invoke methods on the
RemoteServer server object.
The first copy command moves the
RemoteServer class file with its associated
skel and
stub class files to a publicly accessible location in the
/home/zelda/public_html/classes directory, which is on the server machine, so they can be publicly accessed and downloaded. They are placed in the
public_html directory to be under the web server running on the server machine because these files are accessed by client programs using URLs.
The second copy command moves the
Send class file to the same location for the same reason. The
RMIClient1 and
RMIClient2 class files are not made publicly accessible; they communicate from their client machines using URLs to access and download the remote object files in the
public_html directory.
RMIClient1 is invoked from a client-side directory and uses the server-side web server and client-side Java VM to download the publicly accessible files.
RMIClient2 is invoked from a client-side directory and uses the server-side web server and client-side Java VM to download the publicly accessible files.
Start the RMI Registry
Before you start the client programs, you must start the RMI Registry, which is a server-side naming repository that allows remote clients to get a reference to the remote server object.
Before you start the RMI Registry, make sure the shell or window in which you run the
rmiregistry command does not have a
CLASSPATH environment variable that points to the remote object classes, including the
stub and
skel classes, anywhere on your system. If the RMI Registry finds these classes when it starts, it will not load them from the server-side Java VM, which will create problems when clients try to download the remote server classes.
The following commands unset the
CLASSPATH and start the RMI Registry on the default 1099 port. You can specify a different port by adding the port number as follows:
rmiregistry 4444 &. If you specify a different port number, you must specify the same port number in your
server-side code as well.
Unix:
cd /home/zelda/public_html/classes
unsetenv CLASSPATH
rmiregistry &
Win32:
cd \home\zelda\public_html\classes
set CLASSPATH=
start rmiregistry
|
Note: You might want to set the
![]()
CLASSPATHback to its original setting at this point.
![]()
Run the RemoteServer Server Object
To run the example programs, start
RemoteServer first. If you start either
RMIClient1 or
RMIClient2 first, they will not be able to establish a connection because the remote server object is not running.
In this example,
RemoteServer is started from the
/home/zelda/public_html/classes directory.
The lines beginning at
java should be all on one line with spaces where the lines break. The properties specified with the
-D option to the
java interpreter command are program attributes that manage the behavior of the program for this invocation.
Unix:
cd /home/zelda/public_html/classes
java
-Djava.rmi.server.codebase=http://kq6py/~zelda/classes
-Djava.rmi.server.hostname=kq6py.eng.sun.com
-Djava.security.policy=java.policy RemoteServer
Win32:
cd \home\zelda\public_html\classes
java -Djava.rmi.server.codebase=file:
c:\home\zelda\public_html\classes
-Djava.rmi.server.hostname=kq6py.eng.sun.com
-Djava.security.policy=java.policy RemoteServer
|
java.rmi.server.codebase property specifies where the publicly accessible classes are located.
java.rmi.server.hostname property is the complete host name of the server where the publicly accessible classes reside.
java.rmi.security.policy property specifies the
policy file with the permissions needed to run the remote server object and access the remote server classes for download.
RemoteServer).
Run the RMIClient1 Program
Here is the command sequence for the Unix and Win32 platforms; an explanation follows.
In this example,
RMIClient1 is started from the
/home/zelda/classes directory.
The lines beginning at
java should be all on one line with spaces where the lines break. Properties specified with the
-D option to the
java interpreter command are program attributes that manage the behavior of the program for this invocation.
Unix:
cd /home/zelda/classes
java -Djava.rmi.server.codebase=
http://kq6py/~zelda/classes/
-Djava.security.policy=java.policy
RMIClient1 kq6py.eng.sun.com
Win32:
cd \home\zelda\classes
java -Djava.rmi.server.codebase=
file:c:\home\zelda\classes\
-Djava.security.policy=java.policy
RMIClient1 kq6py.eng.sun.com
|
java.rmi.server.codebase property specifies where the publicly accessible classes for downloading are located.
java.security.policy property specifies the
policy file with the permissions needed to run the client program and access the remote server classes.
RMIClient1), and the host name of the server (
Kq6py) where the remote server classes are.
Run RMIClient2
Here is the command sequence for the Unix and Win32 platforms; an explanation follows.
In this example,
RMIClient2 is started from the
/home/zelda/classes directory.
The lines beginning at
java should be all on one line with spaces where the lines break. The properties specified with the
-D option to the
java interpreter command are program attributes that manage the behavior of the program for this invocation.
Unix:
cd /home/zelda/classes
java -Djava.rmi.server.codebase=
http://kq6py/~zelda/classes
-Djava.security.policy=java.policy
RMIClient2 kq6py.eng.sun.com
Win32:
cd \home\zelda\classes
java -Djava.rmi.server.codebase=
file:c:\home\zelda\public_html\classes
-Djava.security.policy=java.policy
RMIClient2 kq6py.eng.sun.com
|
java.rmi.server.codebase property specifies where the publicly accessible classes are located.
java.rmi.server.hostname property is the complete host name of the server where the publicly accessible classes reside.
java.rmi.security.policy property specifies the
policy file with the permissions needed to run the remote server object and access the remote server classes for download.
RMIClient2).
RemoteServer Class
The
RemoteServer class extends
UnicastRemoteObject and implements the
sendData and
getData methods declared in the
Send interface. These are the remotely accessible methods.
UnicastRemoteObject implements a number of
java.lang.Object methods for remote objects and includes constructors and static methods to make a remote object available to receive method calls from client programs.
class RemoteServer extends UnicastRemoteObject
implements Send {
String text;
public RemoteServer() throws RemoteException {
super();
}
public void sendData(String gotText){
text = gotText;
}
public String getData(){
return text;
}
|
The
main method installs the
RMISecurityManager and opens a connection with a port on the machine where the server program runs. The security manager determines whether there is a policy file that lets downloaded code perform tasks that require permissions.
mainRemoteServerkq6pySendBy default the server name uses port 1099. If you want to use a different port number, you can add it with a colon as follows:
kq6py:4444. If you change the port here, you must start the
RMI Registry with the same port number.
The
try block creates an instance of the
RemoteServer class and binds the
name to the remote object to the RMI Registry with the
Naming.rebind(name, remoteServer); statement.
public static void main(String[] args){
if(System.getSecurityManager() == null) {
System.setSecurityManager(new
RMISecurityManager());
}
String name = "//kq6py.eng.sun.com/Send";
try {
Send remoteServer = new RemoteServer();
Naming.rebind(name, remoteServer);
System.out.println("RemoteServer bound");
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot create
remote server object");
} catch (java.net.MalformedURLException e) {
System.out.println("Cannot look up
server object");
}
}
}
|
Note: The
![]()
remoteServerobject is typeSend(see instance declaration at top of class) because the interface available to clients is theSendinterface and its methods; not theRemoteServerclass and its methods.
![]()
Send Interface
The
Send interface declares the methods implemented in the
RemoteServer class. These are the remotely accessible methods.
public interface Send extends Remote {
public void sendData(String text)
throws RemoteException;
public String getData() throws RemoteException;
}
|
RMIClient1 Class
The
RMIClient1 class establishes a connection to the remote server program and sends data to the remote server object. The code to do these things is in the
actionPerformed and
main methods.
actionPerformed Method
The
actionPerformed method calls the
RemoteServer.sendData method to send text to the remote server object.
public void actionPerformed(ActionEvent event){
Object source = event.getSource();
if(source == button){
//Send data over socket
String text = textField.getText();
try{
send.sendData(text);
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot send data to server");
}
textField.setText(new String(""));
}
}
|
main Method
The
main method installs the
RMISecurityManager and creates a
name to use to look up the
RemoteServer server object. The client uses the
Naming.lookup method to look up the
RemoteServer object in the RMI Registry running on the server.
The security manager determines whether there is a policy file that lets downloaded code perform tasks that require permissions.
RMIClient1 frame = new RMIClient1();
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
//args[0] contains name of server where Send runs
String name = "//" + args[0] + "/Send";
send = ((Send) Naming.lookup(name));
} catch (java.rmi.NotBoundException e) {
System.out.println("Cannot look up
remote server object");
} catch(java.rmi.RemoteException e){
System.out.println("Cannot look up
remote server object");
} catch(java.net.MalformedURLException e) {
System.out.println("Cannot look up
remote server object");
}
|
RMIClient2 Class
The
RMIClient2 class establishes a connection with the remote server program and gets the data from the remote server object and displays it. The code to do this is in the
actionPerformed and
main methods.
actionPerformed Method
The
actionPerformed method calls the
RemoteServer.getData method to retrieve the data sent by the client program. This data is appended to the
TextArea object for display to the end user on the server side.
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if(source == button){
try{
String text = send.getData();
textArea.append(text);
} catch (java.rmi.RemoteException e) {
System.out.println("Cannot send data
to server");
}
}
}
}
|
main Method
The
main method installs the
RMISecurityManager and creates a
name to use to look up the
RemoteServer server object. The
args[0] parameter provides the name of the server host. The client uses the
Naming.lookup method to look up the
RemoteServer object in the RMI Registry running on the server.
The security manager determines whether there is a policy file that lets downloaded code perform tasks that require permissions.
RMIClient2 frame = new RMIClient2();
if(System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
String name = "//" + args[0] + "/Send";
send = ((Send) Naming.lookup(name));
} catch (java.rmi.NotBoundException e) {
System.out.println("Cannot look up remote
server object");
} catch(java.rmi.RemoteException e){
System.out.println("Cannot look up remote
server object");
} catch(java.net.MalformedURLException e) {
System.out.println("Cannot look up remote
server object");
}
|
More Information
You can find more information on the RMI API in the RMI trail of The Java Tutorial.
[ TOP]
