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

Remote Method Invocation (Level II)

Migrate an existing remote object

Betty thought the steps to make a remote object activable on demand in the previous section are simple. The key step is to make the remote interface implementation class extend java.rmi.activation.Activatable class. Java language allows a class extends one super class. If the implemention class has to extend another class, how to work a way around? If you have multiple remote objects and need to make them activable on demand, how to do that?

Betty searched the RMI API, found that a static method in Activatable class will work the way just like exportObject() method in UnicastRemoteObject class. The Activatable.exportObject(Remote, ActivationID, portNumber) method will export the remote object on demand.

In order to try out this feature, Betty decided to write a more simple program. A table-talking program came up in her mind. She wrote this program because it is good to encourage people to communicate effectively. It is also a good chance for you to recap the steps you learnt earlier.

She followed these two steps to create a remote object:

  1. Design a remote interface.
  2. Design an implementation class.

Then, she followed three steps to migrate the remote object.

  1. Design a migration class.
  2. Design a set-up program.
  3. Design a client to test the server.

Put all these togeter. She wrote five classes(code listed below);

  1. A remote interface TableTalk,
  2. An implementation class TableTalkImpl
  3. Migration class whose job is to migrate the TableTalkImpl object available for activation.
  4. TableTalkSetup program.
  5. TableTalkClient to test the functionality.

The codes are listed below:

  
//TableTalk.java -- a remote interface
package tabletalking;

import java.rmi.*;

public interface TableTalk extends Remote {
     public String getTopic() throws RemoteException;
}

  
//TableTalkImpl.java -- a remote object
package tabletalking;

import java.rmi.*;

public class TableTalkImpl implements TableTalk {
    private String[] questions = {"What is your favorite time of the day?",
                                  "What is your favorite fruit or vegetable?",
				  "Talk about something beautiful you saw this week.",
                                  "What I like best about our family is ... ",
                                  "Tell about a mistake you have made recently.",
				  "Tell about a time when you felt happy.",
                                  "How do you react when someone crowds in line in front of you?",
                                  "Talk about a special gift that you remember.",
                                  "If your family received a gift of $5,000, how would you like your family to spend it?",
                                  "Tell about a family tradition that you enjoy." 
                                  };
    private int idx = 0;
    	 
    public String getTopic() throws RemoteException {
         idx = (int)(Math.random()*questions.length);
         return questions[idx];
    }
}

  
//Migration.java -- migrate an existing remote object
package tabletalking; 

import java.rmi.*;
import java.rmi.activation.*;

public class Migration implements TableTalk{
    private TableTalkImpl tti = new TableTalkImpl();

    public Migration(ActivationID id, MarshalledObject data) throws RemoteException { 
         Activatable.exportObject(this,id, 0);
    }
    public String getTopic() throws RemoteException {//adaptee
         return tti.getTopic(); 

     }
}

In order to make the migration class work, you have to implement the remote interface. Java allows a class to implement multiple interfaces, so you might implement more interfaces. In this context, TableTalk is the only remote interface.

Note that the remote interface implementation class is a field variable. If you have more remote objects, make them fields in the migration class.

The constructor in the migration class should have ActivationID and MarshalledObject parameters, which are required.

The setup program for the TableTalk program is listed as follows:

  
//TableTalkSetup.java -- a set-up program
package tabletalking; 

import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;

public class TableTalkSetup {
 
    public static void main(String[] args) throws Exception {
	
	System.setSecurityManager(new RMISecurityManager());

	Properties props = new Properties(); 
	props.put("java.security.policy", "/myrmi/myrmi.policy"); 
	
	ActivationGroupDesc.CommandEnvironment ace = null; 
	ActivationGroupDesc exampleGroup = new ActivationGroupDesc(props, ace);
	
	ActivationGroupID agi = 
	   ActivationGroup.getSystem().registerGroup(exampleGroup);
	

	String location = "file:/myrmi/tabletalking/";

	MarshalledObject data = null;

	ActivationDesc desc = new ActivationDesc 
	    (agi, "tabletalking.Migration", location, data);
	
	TableTalk tt = (TableTalk)Activatable.register(desc);
	System.out.println("Got the stub for the TableTalkImpl");

	Naming.rebind("Topic", tt);
	System.out.println("Exported a table-talking object");

	System.exit(0);
    } 
} 

There is nothing new in the setup program. It is almost same as the sample in the previous section, except registering and rebinding a different object, of course a different location for the sytem to look for.

The following is a client class.

  
//TableTalkClient.java -- test the remote object
package tabletalking;

import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class TableTalkClient {
    private static TableTalk stub = null;
    
    private TableTalkClient() {}

    public static void main(String[] args) {

	try {
	    Registry reg = LocateRegistry.getRegistry();
            stub = (TableTalk) reg.lookup("Topic");
            System.out.println("What is the topic for dinner table? \n" + stub.getTopic());	    
	} catch (Exception e) {
	    System.err.println("Client exception thrown: " + e.toString());
	    e.printStackTrace();
	}     
    }
}

The client class is very simple. The highlighted part shows the changes to the previous client class.

It is now to compile and run it. The commands for execution are the same as the previous section.

 C:\   Command Prompt
 
C:\myrmi>javac -d . TableTalk.java TableTalkImpl.java Migration.java TableTalkSe
tup.java TableTalkClient.java

C:\myrmi>set classpath=

C:\myrmi>start rmiregistry

C:\myrmi>start rmid -J-Djava.security.policy=myrmi.policy

C:\myrmi>java -Djava.security.policy=myrmi.policy tabletalking.TableTalkSetup
Got the stub for the TableTalkImpl
Exported a table-talking object

C:\myrmi>java -Djava.security.policy=myrmi.policy tabletalking.TableTalkClient
What is the topic for dinner table?
Talk about something beautiful you saw this week.

C:\myrmi>java -Djava.security.policy=myrmi.policy tabletalking.TableTalkClient
What is the topic for dinner table?
What is your favorite time of the day?

C:\myrmi>java -Djava.security.policy=myrmi.policy tabletalking.TableTalkClient
What is the topic for dinner table?
Tell about a mistake you have made recently.

C:\myrmi>

Please note that two command-line windows will pop up, one for rmiregistry.exe, the other is for rmid.exe. Don't close them before you run the client.

Check your skill

A possible solution for the challenge program

If you have an unsolved problem, please contact javacamp.org

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