|
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:
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
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:
For example,
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:
Example 5-14. ProductImpl.java1. 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.policy1. 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.policy1. grant 2. { 3. permission java.security.AllPermission; 4. }; java.rmi.activation.Activatable 1.2
java.rmi.MarshalledObject 1.2
java.rmi.activation.ActivationGroupDesc 1.2
java.rmi.activation.ActivationGroup 1.2
java.rmi.activation.ActivationSystem 1.2
java.rmi.activation.ActivationDesc 1.2
|
|