Activating an object that does not extend java.rmi.activation.Activatable


This page shows you the steps for enabling an existing class to become activatable. If you are interested in finding out about Creating an Activatable Object or Making a UnicastRemoteObject Activatable, these are also available as tutorials.

Prior to the release of the JDK1.2, an instance of a class that did not extend from UnicastRemoteObject could be accessed from a server program that (1) created an instance of the remote object, and (2) ran all the time. This functionality was provided by creating a constructor which exported the object by calling the static method UnicastRemoteObject.exportObject. The exportObject method accepts as an argument an object that implements an interface that extends from java.rmi.Remote.

Now with the introduction of the class java.rmi.activation.Activatable and the RMI daemon, rmid, programs can be written to register information about remote object implementations that should be created and execute "on demand", rather than running all the time. The RMI daemon, rmid, provides a JVM from which other JVM instances may be spawned. As in the UnicastRemoteObject.exportObject case, activatable objects may be exported using a static method, Activatable.exportObject, and these objects must implement a remote interface.

Note:  For the remainder of this tutorial, the terms "activatable object implementation", "activatable object," and "implementation" may be used interchangeably to refer to  the class, examples.activation.MyClass, which implements a remote interface and is activatable.

This tutorial is organized as follows:

The files needed for this tutorial are: You may notice that while the client code is included, it is not discussed in a step-by-step manner, like the implementation and setup classes. The reason for this omission, is that the client code for activatable objects is no different than the RMI client code for accessing non-activatable remote objects.  Activation is strictly a server-side implementation decision.

For all of the source code used in the activation tutorials, you may choose from these formats:


Creating the remote interface

Create an interface that describes each of the methods that you would like to call remotely. For this example, the remote interface will be examples.activation.AnotherRemoteInterface.  There are three steps to create a remote interface.

  1. Make the appropriate imports in the interface
  2. Extend java.rmi.Remote
  3. Declare each of the methods that may be called remotely
  4. Step 1:
    Make the appropriate imports in your interface
     
    import java.rmi.*;

    Step 2:
    Extend java.rmi.Remote

    public interface AnotherRemoteInterface extends Remote {
     

    Step 3:
    Declare each of the methods that may be called remotely

    public String calltheServer(String s) throws RemoteException;


    Creating the implementation class

    For this example, the implementation class will be examples.activation.MyClass. There are three steps to migrate a class which does not extend Activatable or UnicastRemoteObject to become activatable:
     

    1. Make the appropriate imports in the implementation class
    2. Modify the class declaration so that the class now implements

    3. an interface that extends from java.rmi.Remote
    4. Declare a two-argument constructor in the implementation class

    5.  

    Creating the "setup" class

    The job of the "setup" class is to create all the information necessary for the activatable class, without necessarily creating an instance of the remote object. For this example, the setup class will be examples.activation.Setup3.

    The setup class passes information about the activatable class to rmid, registers a remote reference (an instance of the activatable class's stub class) and an identifier (name) with the rmiregistry, and then the setup class may exit.  There are six steps to create a setup class:
     

    1. Make the appropriate imports
    2. Install a SecurityManager
    3. Create an ActivationDesc instance
    4. Declare an instance of your remote interface and register with rmid
    5. Bind the stub to a name in the rmiregistry
    6. Quit the setup application
    7. Step 1:
      Make the appropriate imports in the setup class
       


    Compile and run the code

    There are six steps to compile and run the code:
     

    1. Compile the remote interface, implementation, client and setup classes
    2. Run rmic on the implementation class
    3. Start the rmiregistry
    4. Start the activation daemon, rmid
    5. Run the setup program
    6. Run the client
    7. 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
       
      In order to run this code on your system, you'll need to change the location of the policy file to be the location of the directory on your system, where you've installed the example source code.

      % rmiregistry -J-Djava.security.policy=/home/rmi_tutorial/activation/policy &

      Note: In this example, for simplicity,  we will use a policy file that gives global permission to anyone from anywhere. Do not use this policy file in a production environment. For more information on how to properly open up permissions using a java.security.policy file, please refer to to the following documents:
       

        http://java.sun.com/products/jdk/1.2/docs/guide/security/PolicyFiles.html
        http://java.sun.com/products/jdk/1.2/docs/guide/security/permissions.html
     

    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 impleemntation
              //
              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);
          }

      }

     


    Copyright © 1998 Sun Microsystems, Inc. All Rights Reserved.