SDSU CS 696 Emerging Technologies: Java Distributed Computing
Spring Semester, 1999
Remote Object Activation
Previous    Lecture Notes Index    Next    
© 1999, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 02-Mar-99

Contents of Doc 11, Remote Object Activation


References


Activation Tutorials
Local HTML Copy: http://www-rohan.sdsu.edu/java/jdk1.2/docs/guide/rmi/activation.html
Sun HTML Site: http://java.sun.com/products/jdk/1.2/docs/guide/rmi/activation.html
Java Remote Method Invocation Specification, chapter 7
Local HTML Copy: http://www-rohan.sdsu.edu/java/jdk1.2/docs/guide/rmi/spec/rmiTOC.doc.html
Sun HTML Site: http://java.sun.com/products/jdk/1.2/docs/guide/rmi/spec/rmiTOC.doc.html
Hard copy is on reserve at Love Library
JDK 1.2 API Documentation
Local Copy: http://www-rohan.sdsu.edu/java/jdk1.2/docs/api/overview-summary.html
Sun Site: http://java.sun.com/products/jdk/1.2/docs/api/overview-summary.html

RMI Source Code
On rohan at /opt/jdk1.2/src


Doc 11, Remote Object Activation Slide # 2

Remote Object Activation


Activation allows objects to begin execution on an as-needed basis

Active object
Remote object implementation that is instantiated and exported in a JVM

Passive object
An object that is not yet instantiated or exported in a JVM, but which can be brought into an active state

Activation
Transforming a passive object into an active object

Lazy activation
Delay activation until the first client request for the object
Uses faulting remote references

Faulting remote reference (or fault block)
Causes the activation of a remote object the first time a method on the object is called
The faulting remote reference contains a persistent activation handle (reference) for the remote object and a transient remote reference to the remote object. The transient remote reference can be null. On the first reference to the remote object, if the transient remote reference is null, the persistent activation handle is used to contact (directly or indirectly) the activator for the remote object. If need be the activator activates the object and returns the proper remote reference to the remote object.

Activator
Manages the activation of objects


Doc 11, Remote Object Activation Slide # 3

Information Needed to Activate an Object


Object initialization data
Not all objects can be created with a no-argument constructor

Objects class name

Location of the object’s class code (In URL format)

Reference to the JVM in which to activate the object
Since the JVM that housed the object may no longer be running it will have to be started. This means that any command line flags needed to start the JVM are needed. Any system properties that need special values must be handled. The policy file for the JVM must also be set.

Object Initialization Data


java.rmi.MarshalledObject is used to provide data to an object for initialization. MarshalledObject is a wrapper function that is used to serialize/deserialize initialization data. All initialization data must be serializable. MarshalledObject can hold only one object. If you need more than one piece of initialization data, put them in a container, then use MarshalledObject.


MarshalledObject


MarshalledObject(Object initializationData)
Create MarshalledObject which contains the initializationData object

Methods
equals(Object obj)
hashCode()
get()
get returns the one object stored in the MarshalledObject


Doc 11, Remote Object Activation Slide # 4

Activator


The entity that supervises activation by being:

A database of information needed to activate objects
A manager of JVMs on the same machine, that contains active objects

Normally there is one activator per host machine.

rmid is the activator provided with JDK 1.2

You start rmid with the command:

rmid [-port port] [-log dir]
If –port is not given, it uses 1098

-log directory is the location rmid stores its database. If this is not given, it uses the directory "log" in the directory in which rmid was started

Doc 11, Remote Object Activation Slide # 5

Activation Group


The activation group is the entity in a JVM which:
Receives the requests to activate an object in the JVM and
Returns the activated object reference back to the activator

The activator is normally the one to interact with the activation group in a JVM

Each activation group has an


The ActivationGroupID

The activator may need to start a JVM for the activation group. In order to do this the activator needs to know what special information is needed by the JVM on start up. This can include special values of System properties and command line arguments to the JVM ( setting memory space, etc). The ActivationGroupDesc is used to provide this information.


Doc 11, Remote Object Activation Slide # 6

ActivationGroupDesc

Constructors
ActivationGroupDesc(Properties overrides, 
      ActivationGroupDesc.CommandEnvironment cmd)
Overrides
The properties to set when the group is recreated
These properties will be used to override the standard value of System properties when starting the JVM for the activation group

ActivationGroupDesc.CommandEnvironment
Contains command line arguments used to start the JVM for the activation group

ActivationGroupDesc(String className, 
      String location, 
      MarshalledObject data,
      Properties overrides, 
      ActivationGroupDesc.CommandEnvironment cmd) 
Specifies an alternate ActivationGroup implementation (className, location, data) and execution environment to be used for the group. The className, location, and data are used to create the ActivationGroup. The className is the name of the subclass of ActivationGroup to be used. Location is the location of this class. Data is the initialization data that the class may need. This form of the constructor is for advanced uses.

Doc 11, Remote Object Activation Slide # 7

Example – No Initialization Data

Remote Interface
package whitney.rmi.examples.activation;
public interface Hello extends java.rmi.Remote  {
   String sayHello() throws java.rmi.RemoteException;
}

Implementation

The second argument in super( id, 0 ) is the port number to export the remote object on. Using 0 results in a random port being used.
package whitney.rmi.examples.activation;
import java.net.InetAddress;
import java.rmi.*;
import java.rmi.activation.*;
public class HelloServer extends Activatable implements Hello {
   public HelloServer(ActivationID id, MarshalledObject data) 
      throws RemoteException  {
      super( id, 0 );
      System.out.println( "HelloServer object created");
   }
   public String sayHello()  {
      return  "Hello World from " + getHostName();
   }
   protected static String getHostName()  {
      try  {
         return InetAddress.getLocalHost().getHostName();
      } catch (java.net.UnknownHostException who)  {
         return "Unknown";
      }
   }
}

Doc 11, Remote Object Activation Slide # 8

Setup Class

package whitney.rmi.examples.activation;
import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;
public class RegisterHelloServer {
   public static void main(String[] args) throws Exception  {
      System.setSecurityManager(new RMISecurityManager());
      Properties policyFileLocation = new Properties(); 
      policyFileLocation.put("java.security.policy", 
                                 "/export/home/whitney/.java.policy");
      ActivationGroupDesc.CommandEnvironment ace = null; 
      ActivationGroupDesc exampleGroup = 
         new ActivationGroupDesc(policyFileLocation, ace);
 
       ActivationSystem localActivationSystem = ActivationGroup.getSystem();
      ActivationGroupID agi = 
         localActivationSystem.registerGroup(exampleGroup);
      ActivationGroup.createGroup(agi, exampleGroup, 0);
      String classLocation = "file:/export/home/whitney/java/classes/";
      String serverClass = 
         "whitney.rmi.examples.activation.HelloServer";
      MarshalledObject data = null;
      ActivationDesc desc = 
         new ActivationDesc(serverClass, classLocation, data);
      
      Hello mri = (Hello)Activatable.register(desc);
      System.out.println("Got the stub for the HelloServer");
         
      Naming.rebind("HelloServer", mri);
      System.out.println("Exported HelloServer");
      System.exit(0);
      }
   }

Doc 11, Remote Object Activation Slide # 9

Setup Class Explained


Security manager is needed
      System.setSecurityManager(new RMISecurityManager());
We need to create the ActivationGroup.

Set the policy file that will be used in the JVM that creates and runs the server object

      Properties policyFileLocation = new Properties(); 
      policyFileLocation.put("java.security.policy", 
                                 "/export/home/whitney/.java.policy");
No special command line arguments are used in starting up the JVM for this activation group
      ActivationGroupDesc.CommandEnvironment ace = null; 
      ActivationGroupDesc exampleGroup = 
         new ActivationGroupDesc(policyFileLocation, ace);
Register the group with the Activation System to get the system wide unique ID
       ActivationSystem localActivationSystem = ActivationGroup.getSystem();
      ActivationGroupID agi = 
         localActivationSystem.registerGroup(exampleGroup);
Now create the group in the local JVM
The third parameter is the group's incarnation number. Set it to zero on group's initial creation.
      ActivationGroup.createGroup(agi, exampleGroup, 0);

Doc 11, Remote Object Activation Slide # 10
Now we need to create the ActivationDesc for the activatable object

      String classLocation = "file:/export/home/whitney/java/classes/";
      String serverClass = 
         "whitney.rmi.examples.activation.HelloServer";
Since the server object needs no initialization data we set data to null

      MarshalledObject data = null;
      ActivationDesc objectDescriptor = 
         new ActivationDesc(serverClass, classLocation, data);

Now we register the descriptor to get a remote reference to the passive object

      Hello helloStub = (Hello)Activatable.register(objectDescriptor );
      System.out.println("Got the stub for the HelloServer");

Register the stub with the rmiregistry

      Naming.rebind("HelloServer", helloStub );
      System.out.println("Exported HelloServer");
We are done, so can exit
      System.exit(0);
      }
   }

Doc 11, Remote Object Activation Slide # 11
A sample Client

package whitney.rmi.examples.activation;
import java.rmi.registry.Registry;
import java.rmi.RemoteException;
import whitney.rmi.tools.ServerTester;
public class HelloClient extends ServerTester 
   {
   public void test() throws RemoteException, InterruptedException
      {
      Hello myServer = (Hello) serverObject;
      System.out.println( myServer.sayHello() );
      }
   }
ServerTester is on Doc 9 slide 2 at: http://www.eli.sdsu.edu/courses/spring99/cs696/notes/roaming/roaming.html#Heading4

Doc 11, Remote Object Activation Slide # 12
Running The Example

Compile client, server, etc.

Generate stubs and skeletons using rmic on server class

Start the rmiregistry

Start the activation daemon rmid

Run the setup program

Run the client

Note you can stop the rmid using:

   rmid –stop
When you resume rmid, you can still connect to the server object.

Doc 11, Remote Object Activation Slide # 13

Example With Initialization Data


In this example a counter object will save is state in a file. When the object is restarted, it will read the file for the last value of the count.
Counter Interface
package whitney.rmi.examples.activation;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Counter extends Remote
   {
   public abstract void reset() throws RemoteException;
   public abstract int increase() throws RemoteException;
   public abstract int decrease() throws RemoteException;
   public abstract int count()  throws RemoteException;
   }

Doc 11, Remote Object Activation Slide # 14

Counter Implementation

package whitney.rmi.examples.activation;
import sdsu.io.SimpleFile;
import java.rmi.activation.*;
import java.rmi.*;
import java.io.IOException;
public class PersistentCounter extends Activatable implements Counter {
   private SimpleFile previousStateFile;
   private int count = 0;
   public PersistentCounter( ActivationID id, MarshalledObject data) 
      throws RemoteException, ClassNotFoundException, IOException {
      super(id, 0);
      previousStateFile = (SimpleFile)data.get();
      if (previousStateFile.exists()) 
         this.restoreState();
   }
   
   private void restoreState() throws IOException {
      String previousState = previousStateFile.getContents();
      count = Integer.parseInt( previousState );
   }
      
   private void saveState() throws RemoteException {
      try  {
         previousStateFile.setContents( String.valueOf( count ));
      } catch (IOException writeProblem ) {
         throw new RemoteException( "Problem saving count" );
      }
   }

Doc 11, Remote Object Activation Slide # 15
PersistentCounter Continued
   public void reset() throws RemoteException {
      count = 0;
      saveState();
   }
   public int increase() throws RemoteException {
      ++count;
      saveState();
      return count;
   }
   public int decrease() throws RemoteException {
      --count;
      saveState();
      return count;
   }
   public int count() {
      return count;
   }
}

Doc 11, Remote Object Activation Slide # 16

The Counter Setup

package whitney.rmi.examples.activation;
import java.rmi.*;
import java.rmi.activation.*;
import java.util.Properties;
import sdsu.io.SimpleFile;
public class RegisterPersistentCounter {
   public static void main(String[] args) throws Exception  {
      System.setSecurityManager(new RMISecurityManager());
      Properties policyFileLocation = new Properties(); 
      policyFileLocation.put("java.security.policy", "/export/home/whitney/.java.policy");
      ActivationGroupDesc.CommandEnvironment ace = null; 
      ActivationGroupDesc exampleGroup = 
         new ActivationGroupDesc(policyFileLocation, ace);
 
      ActivationGroupID agi = 
         ActivationGroup.getSystem().registerGroup(exampleGroup);
      ActivationGroup.createGroup(agi, exampleGroup, 0);
      String classLocation = "file:/export/home/whitney/java/classes/";
      String serverClass = 
         "whitney.rmi.examples.activation.PersistentCounter";
      String countFileName = 
         "/export/home/whitney/java/whitney/rmi/examples/activation/CountFile";
      SimpleFile countDataFile = new SimpleFile( countFileName );
      MarshalledObject data = new MarshalledObject( countDataFile );
      ActivationDesc desc = new ActivationDesc(serverClass, classLocation, data);
      
      Counter mri = (Counter)Activatable.register(desc);
      System.out.println("Got the stub for the PersistentCounter");
         
      Naming.rebind("Counter", mri);
      System.out.println("Exported Counter");
      System.exit(0);
      }
   }

Doc 11, Remote Object Activation Slide # 17

What is New in the Setup


The counter needs to know the location of data file containing its previous state. When a passive object is activated it will use this information to reset its state.

      String classLocation = "file:/export/home/whitney/java/classes/";
      String serverClass = 
         "whitney.rmi.examples.activation.PersistentCounter";
Create the file object to the data file

      String countFileName = 
         "/export/home/whitney/java/whitney/rmi/examples/activation/CountFile";
      SimpleFile countDataFile = new SimpleFile( countFileName );
Wrap the file object, so it can be delivered to the counter

      MarshalledObject data = new MarshalledObject( countDataFile );
      ActivationDesc desc = 
         new ActivationDesc(serverClass, classLocation, data);

Doc 11, Remote Object Activation Slide # 18

Lazy Activation vs. Activation on Startup


The default behavior is to activate passive object when first requested. One can set it so that when the rmid is restarted a passive object is activated. ActivationDesc has a constructor that contains a restart flag.


public ActivationDesc(String className, String location,
      MarshalledObject data,  boolean restart)
   throws ActivationException

Constructs an object descriptor for an object whose class name is className, that can be loaded from the code location and whose initialization information is data. If this form of the constructor is used, the groupID defaults to the current id for ActivationGroup for this VM. All objects with the same ActivationGroupID are activated in the same VM.

This constructor will throw ActivationException if there is no current activation group for this VM. To create an ActivationGroup use the ActivationGroup.createGroup method.

Parameters:
className - the object's fully package qualified class name
location - the object's code location (from where the class is loaded)
data - the object's initialization (activation) data contained in marshalled form.
restart - if true, the object is restarted when the activator is restarted; if false, the object is activated on demand.


Copyright ©, All rights reserved.
1999 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.

Previous    visitors since 02-Mar-99    Next