Server Object Activation


In the preceding sample programs, we used a server program to instantiate and register objects so that clients could make remote calls on them. However, in some cases, it may be wasteful to instantiate lots of server objects and have them wait for connections, whether or not client objects use them. The activation mechanism lets you delay the object construction so that a server object is only constructed when at least one client invokes a remote method on it.

To take advantage of activation, the client code is completely unchanged. The client simply requests a remote reference and makes calls through it.

However, the server program is replaced by an activation program that constructs activation descriptors of the objects that are to be constructed at a later time, and binds receivers for remote method calls with the naming service. When a call is made for the first time, the information in the activation descriptor is used to construct the object.

A server object that is used in this way should extend the Activatable class and, of course, implement one or more remote interfaces. For example,

 class ProductImpl    extends Activatable    implements Product {    . . . } 

Because the object construction is delayed until a later time, it must happen in a standardized form. Therefore, you must provide a constructor that takes two parameters:

  • An activation ID (which you simply pass to the superclass constructor)

  • A single object containing all construction information, wrapped in a MarshalledObject

If you need multiple construction parameters, you must package them in a single object. You can always use an Object[] array or an ArrayList. As you will soon see, you place a serialized (or marshalled) copy of the construction information inside the activation descriptor. Your server object constructor should use the get method of the MarshalledObject class to deserialize the construction information.

In the case of the ProductImpl class, this procedure is quite simpleonly one piece of information is necessary for construction, namely, the product name. That information can be wrapped into a MarshalledObject and unwrapped in the constructor:

 public ProductImpl(ActivationID id, MarshalledObject data) {    super(id, 0);    name = (String) data.get();;    System.out.println("Constructed " + name); } 

By passing 0 as the second parameter of the superclass constructor, we indicate that the RMI library should assign a suitable port number to the listener port.

This constructor prints a message so that you can see that the product objects are activated on demand.

NOTE

Your server objects don't actually have to extend the Activatable class. If they don't, then place the static method call

 Activatable.exportObject(this, id, 0) 

in the constructor of the server class.


Now let us turn to the activation program. First, you need to define an activation group. An activation group describes common parameters for launching the virtual machine that contains the server objects. The most important parameter is the security policy.

As with our other server objects, we do not check for security. (Presumably, the objects come from a trusted source.) However, the virtual machine in which the activated objects run has a security manager installed. To enable all permissions, supply a file server.policy with the following contents:

 grant {    permission java.security.AllPermission; }; 

Construct an activation group descriptor as follows:

 Properties props = new Properties(); props.put("java.security.policy", "/server/server.policy"); ActivationGroupDesc group = new ActivationGroupDesc(props, null); 

The second parameter describes special command options; we don't need any for this example, so we pass a null reference.

Next, create a group ID with the call

 ActivationGroupID id = ActivationGroup.getSystem().registerGroup(group); 

Now you are ready to construct the activation descriptors. For each object that should be constructed on demand, you need the following:

  • The activation group ID for the virtual machine in which the object should be constructed;

  • The name of the class (such as "ProductImpl" or "com.mycompany.MyClassImpl");

  • The URL string from which to load the class files. This should be the base URL, not including package paths;

  • The marshalled construction information.

For example,

[View full width]

MarshalledObject param = new MarshalledObject("Blackwell Toaster"); ActivationDesc desc = new ActivationDesc(id, "ProductImpl", "http://myserver.com/download /", param);

Pass the descriptor to the static Activatable.register method. It returns an object of some class that implements the remote interfaces of the implementation class. You can bind that object with the naming service:

 Product p = (Product) Activatable.register(desc); namingContext.bind("toaster", p); 

Unlike the server programs of the preceding examples, the activation program exits after registering and binding the activation receivers. The server objects are constructed only when the first remote method call occurs.

Examples 5-14 and 5-15 show the code for the activatable product implementation and the activation program. The product interface and the client program are unchanged.

To launch this program, follow these steps:

1.

Compile all source files.

2.

If you use JDK 1.4 or below, run rmic to generate a stub for the ProductImpl class:

 rmic -v1.2 ProductImpl 

3.

Start the RMI registry.

4.

Start the RMI activation daemon.

 rmid -J-Djava.security.policy=rmid.policy & 

or

 start rmid -J-Djava.security.policy=rmid.policy 

The rmid program listens to activation requests and activates objects in a separate virtual machine. To launch a virtual machine, the rmid program needs certain permissions. These are specified in a policy file (see Example 5-16). Use the -J option to pass an option to the virtual machine running the activation daemon.

5.

Run the activation program. In this setup, we assume that you start the program in the directory that contains the class files and the server policy file.

 java ProductActivator 

The program exits after the activation receivers have been registered with the naming service.

6.

Run the client program

 java -Djava.security.policy=client.policy ProductClient 

The client will print the familiar product descriptions. When you run the client for the first time, you will also see the constructor messages in the server shell window.

Example 5-14. ProductImpl.java
  1. import java.rmi.*;  2. import java.rmi.server.*;  3.  4. /**  5.    This is the implementation class for the remote product  6.    objects.  7. */  8. public class ProductImpl  9.    extends UnicastRemoteObject 10.    implements Product 11. { 12.    /** 13.       Constructs a product implementation 14.       @param n the product name 15.    */ 16.    public ProductImpl(String n) throws RemoteException 17.    { 18.       name = n; 19.    } 20. 21.    public String getDescription() throws RemoteException 22.    { 23.       return "I am a " + name + ". Buy me!"; 24.    } 25. 26.    private String name; 27. } 

Example 5-15. ProductActivator.java

[View full width]

  1. import java.io.*;  2. import java.net.*;  3. import java.rmi.*;  4. import java.rmi.activation.*;  5. import java.util.*;  6. import javax.naming.*;  7.  8. /**  9.    This server program activates two remote objects and 10.    registers them with the naming service. 11. */ 12. public class ProductActivator 13. { 14.    public static void main(String args[]) 15.    { 16.       try 17.       { 18.          System.out.println("Constructing activation descriptors..."); 19. 20.          Properties props = new Properties(); 21.          // use the server.policy file in the current directory 22.          props.put("java.security.policy", new File("server.policy").getCanonicalPath()); 23.          ActivationGroupDesc group = new ActivationGroupDesc(props, null); 24.          ActivationGroupID id = ActivationGroup.getSystem().registerGroup(group); 25.          MarshalledObject p1param = new MarshalledObject("Blackwell Toaster"); 26.          MarshalledObject p2param = new MarshalledObject("ZapXpress Microwave Oven"); 27. 28.          String classDir = "."; 29.          // turn the class directory into a file URL 30.          // for this demo we assume that the classes are in the current dir 31.          // we use toURI so that spaces and other special characters in file names are  escaped 32.          String classURL = new File(classDir).getCanonicalFile().toURI().toString(); 33. 34.          ActivationDesc desc1 = new ActivationDesc(id, "ProductImpl", classURL, p1param); 35.          ActivationDesc desc2 = new ActivationDesc(id, "ProductImpl", classURL, p2param); 36. 37.          Product p1 = (Product) Activatable.register(desc1); 38.          Product p2 = (Product) Activatable.register(desc2); 39. 40.          System.out.println("Binding activable implementations to registry..."); 41.          Context namingContext = new InitialContext(); 42.          namingContext.bind("rmi:toaster", p1); 43.          namingContext.bind("rmi:microwave", p2); 44.          System.out.println("Exiting..."); 45.       } 46.       catch (Exception e) 47.       { 48.          e.printStackTrace(); 49.       } 50.    } 51. } 

Example 5-16. rmid.policy
 1. grant 2. { 3.    permission com.sun.rmi.rmid.ExecPermission 4.       "${java.home}${/}bin${/}java"; 5.    permission com.sun.rmi.rmid.ExecOptionPermission 6.       "-Djava.security.policy=*"; 7. }; 

Example 5-17. server.policy
 1. grant 2. { 3.    permission java.security.AllPermission; 4. }; 


 java.rmi.activation.Activatable 1.2 

  • protected Activatable(ActivationID id, int port)

    constructs the activatable object and establishes a listener on the given port. Use 0 for the port to have a port assigned automatically.

  • static Remote exportObject(Remote obj, ActivationID id, int port)

    makes a remote object activatable. Returns the activation receiver that should be made available to remote callers. Use 0 for the port to have a port assigned automatically.

  • static Remote register(ActivationDescriptor desc)

    registers the descriptor for an activatable object and prepares it for receiving remote calls. Returns the activation receiver that should be made available to remote callers.


 java.rmi.MarshalledObject 1.2 

  • MarshalledObject(Object obj)

    constructs an object containing the serialized data of a given object.

  • Object get()

    deserializes the stored object data and returns the object.


 java.rmi.activation.ActivationGroupDesc  1.2 

  • ActivationGroupDesc(Properties props, ActivationGroupDesc.CommandEnvironment env)

    constructs an activation group descriptor that specifies virtual machine properties for a virtual machine that hosts activated objects. The env parameter contains the path to the virtual machine executable and command-line options, or it is null if no special settings are required.


 java.rmi.activation.ActivationGroup 1.2 

  • static ActivationSystem getSystem()

    returns a reference to the activation system.


 java.rmi.activation.ActivationSystem 1.2 

  • ActivationGroupID registerGroup(ActivationGroupDesc group)

    registers an activation group and returns the group ID.


 java.rmi.activation.ActivationDesc 1.2 

  • ActivationDesc(ActivationGroupID id, String className, String classFileURL, MarshalledObject data)

    constructs an activation descriptor.



    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net