Previous lesson 1/6 |home| Next lesson 3/6

Remote Method Invocation (Level II)

Use different host and port number

Betty thought in future she might publish several calculators in one RMI server,like moving calculator, cost of living calculator, salary calculator, etc. That means she will make many remote objects, but how to register multiple remote objects to one or different TCP port numbers.

She kept these doubts in mind and went to the RMI specification and API to search for an answer, she found that on the server side, she could use UnicastRemoteObject.exportObject(Remote, int) method to register port number when starting the server. So, she decided to obtain the port number from command-line and made the server printout more meaningful by using InetAddress.getLocalHost().getHostName() method.

The alteration made in Server.java is highlighted as follows:

 
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.net.InetAddress;
	
public class Server {
	
    public Server() {}

    public static void main(String args[]) {
	int port = Integer.parseInt(args[0]);
	try {
	    PaymentImpl robj = new PaymentImpl();
	    Payment stub = (Payment) UnicastRemoteObject.exportObject(robj, port);

	    Registry registry = LocateRegistry.getRegistry();
	    registry.bind("Mortgage", stub);
            System.out.print("Mortgage Server is ready to listen on ");
            System.out.println(InetAddress.getLocalHost().getHostName());
	} catch (Exception e) {
	    System.err.println("Server exception thrown: " + e.toString());
	    e.printStackTrace();
	}
    }
}

Note that she can use any port number she wants when she starts the server. On the client side, the getRegistry(port) will get the registry on the server if it is local host or use getRegistry(String host, int port) for a different host and port. And the reg.lookup(remoteObjName)method will find the remote object by its name and return a remote reference. Note that you should use a unique name to avoid name conflicts. She also added some code in server printout in case you run the client in a different computer, you can use the machine name to make a connection.

When you run the server, the printout would be:

 C:\   Command Prompt
 

Mortgage Server is ready to listen on Betty

Here the "Betty" is the name of computer that Betty used to run the server.

She re-compiled the source code, executed it and got exact printout, but this time the remote object is registered at TCP port 2004, not the default number 1099.

Note that you can choose a TCP port number from 1 to 65535 at least. But don't use the numbers that are already used by other servers. Like port# 25 for smtp, port# 13 for daytime, port# 80 for http, etc.

The working result is as follows:

 C:\   Command Prompt
 

C:\myrmi>javac -d . Payment.java PaymentImpl.java Server.java Client.java

C:\myrmi>set classpath=

C:\myrmi>start rmiregistry

C:\myrmi>start java Server 2004

C:\myrmi>java Client
Usage: java Client principal annualInterest years

For example: java Client 80000 .065 15

You will get the output like the following:

The principal is $80000
The annual interest rate is 6.5%
The term is 15 years
Your monthly payment is $696.89

C:\myrmi>java Client 150000 .060 15
The principal is $150000
The annual interest rate is 6.0%
The term is 15 years
Your monthly payment is $1265.79

C:\myrmi>

You may use one TCP port number to register multiple remote objects, or use one client to access multiple remote objects at the same port. Try it by yourself.

Betty thought what about different host? If the host is located thousand miles away how to use code to contact?

Betty did a little research, came out that she could use java.rmi.server.codebase property to download the stub class, or any serialized class(a class that implements Serializable interface) by using the following commands. Let's say that the remote class named Mortgage in http://www.javacamp.org/rmi/mortgagecalculator/ sub-directory (Don't try it, javacamp.org is not hosted by Java technology for the moment). You can run your server in the following way:

 C:\   Command Prompt
 

C:\myrmi\java -Djava.rmi.server.codebase=http://www.javacamp.org/rmi/mortgagecalculator/ Client

Note that java.rmi.server.codebase accepts http://, ftp: and file:\\\ protocols. If you want to download a file from your local file system, let's say that the stub class is at C:\myrmi\ directory, you may use the following command:

 C:\   Command Prompt
 

C:\myrmi\java -Djava.rmi.server.codebase=file:\\\myrmi\ Client

Note that the trailing slash in this case is required for a remote class. If the remote object is bundled with a jar file, you may need to give exact location:

 C:\   Command Prompt
 

C:\myrmi\java -Djava.rmi.server.codebase=http://some.com/somedir/Mortgage.jar Client

Note that the "-D" option here specify the system property.

Betty thought it would be better if she could use code to do RMI registry instead of using command-line commands. She went to Java API to look for solution and came up with the following result.

How to use code to do RMI registry?

Assume the port number is 2004, you may code as follows:

 
 //in your server program
  LocateRegistry.createRegistry(2004);
  Registry registry = LocateRegistry.getRegistry(2004);

 //in your client program
  Registry registry = LocateRegistry.getRegistry(2004);

If the RMI server is located somewhere, use:
  Registry registry = LocateRegistry.getRegistry(hostName, 2004);

If you use the above code in your server and client programs respectively, you don't need to use start rmiregistry command to start RMI registry manually before you start your server.

According to the RMI specification, to access a remote object, a security manager should be installed and a policy file should be used. How to do that, please go through the next section.

Check your skill

A possible solution:

 
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
	
public class HelloServer {
	
    public HelloServer() {}

    public static void main(String args[]) {
	int port = Integer.parseInt(args[0]);
	try {
	    HelloImpl robj = new HelloImpl();
	    Hello stub = (Hello) UnicastRemoteObject.exportObject(robj, port);

	    // Bind the remote object's stub in the registry
	    Registry registry = LocateRegistry.getRegistry();
	    registry.rebind("Hello", stub);
            System.out.println("Hello Server is ready to listen...");

	} catch (Exception e) {
	    System.err.println("Server exception thrown: " + e.toString());
	    e.printStackTrace();
	}
    }
}

java HelloServer 1234

A possible solution for coding RMI registry:

 
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
	
public class HelloServer {
	
    public HelloServer() {}

    public static void main(String args[]) {
	int port = Integer.parseInt(args[0]);
	try {
	    HelloImpl robj = new HelloImpl();
	    Hello stub = (Hello) UnicastRemoteObject.exportObject(robj, port);
            
            LocateRegistry.createRegistry(port);    
	    Registry registry = LocateRegistry.getRegistry(port);
	    registry.rebind("Hello", stub);
            System.out.println("Hello Server is ready to listen at port: " + port);

	} catch (Exception e) {
	    System.err.println("Server exception thrown: " + e.toString());
	    e.printStackTrace();
	}
    }
}

java HelloServer 1234

Previous lesson 1/6 |home| Next lesson 3/6