Chapter 10. Servers II—activation

  • Introduction—First principles—How it works—Writing an activatable server—Registration—Building an activatable server—Runtime setup—the Unreferenced interface—Which servers should be activatable—Activation system as a registry—Debugging—Activation Groups in Win32—Activation Clients—Remarks—Exercises

In this chapter

In Chapter 7 we discussed the “unicast” server—the simplest form of RMI server. This chapter builds on the information provided there and describes how to write activatable servers—servers that can be activated by the activation system if they are not already running. You can find out more about other server types in Chapter 14 and Chapter 17.

Introduction

As we have seen, “unicast” RMI servers are based on the UnicastRemoteObject class, or exported by its static exportObject method. A client's remote reference to such an RMI server remains valid as long as the server itself remains running, and no longer. Once the server has exited, or has been unexported, the reference is no longer of any use. It no longer refers to anything. It will fail if the client uses it to invoke a remote method. It cannot usefully be saved and restored across a system shutdown. A client of such a server has to go through the process of obtaining a remote reference (a stub) every time it runs, starting with a registry lookup.

Activation removes this restriction. A remote reference to an “activatable” RMI server remains valid for as long as the server it refers to remains registered with the RMI activation system. Any time the reference to the server is used, the server will be automatically restarted by the activation system if it is not currently running. The remote reference itself can usefully be saved and restored across system shutdowns.

You can think of a remote reference to an activatable object as a “ persistent” reference.

Uses of activation

Activation is useful in a number of circumstances:

  • on-demand servers

  • persistent or fault-tolerant servers

  • servers which must be available on a “24×7” schedule (24 hours per day, 7 days per week).

First principles—activation

Activatable servers

An activatable server is one which the activation system can activate—create—on demand. To be activatable, an RMI server must:

  • implement a remote interface

  • be registered with the activation system

  • have an accessible constructor of a particular form for invocation by the activation system

  • export itself when so constructed, either by calling the appropriate constructor in Activatable, if the class is derived from Activatable, otherwise by calling Activatable.exportObject.

An activatable server is registered by calling Activatable.register. When registered, it is associated with an activation group, a codebase, and a (possibly null) initial argument.

We deliberately use the term “activatable server” rather than “activatable class”. An activatable server is specified by its activation descriptor, i.e. by the tuple of {activation group ID, codebase, class, initialization argument}. The activatable class is only one element of the tuple.

Activation groups

An activatable server is registered in a specific activation group.

An activation group is a group of zero or more activatable servers. Each activation group runs in a separate Java virtual machine. An activation group is registered with the activation system. When required, it is created by the activation system in a its own JVM.

The RMI activation system is an instance of the interface ActivationSystem provided by the implementation. In the Sun JDK it is provided in the form of the rmid program. A reference to the activation system is obtained via the static method ActivationGroup.getSystem.

The codebase of an activatable server is the URL at which its class files can be found. This is the same concept as the normal RMI codebase.

The initialization argument of an activatable server is a MarshalledObject which is supplied to the constructor invoked by the activation system during activation. This MarshalledObject is initially constructed by the program which registers the server. It may contain anything you like as long as it is serializable; it may contain nothing, or it may be null.

An activatable server can change its own initialization argument, by obtaining its own activation descriptor—via ActivationSystem.getActivationDesc—and then resetting the activation descriptor with a new value for the initialization argument—via ActivationSystem.setActivationDesc. This technique is useful for activatable servers which require progressively different initialization arguments for each activation. In other words, this mechanism provides a simple way for an activatable server to save and restore its own status. The initialization argument can be null at any stage of this process, including the initial stage.

How it works

Figure 10.1 shows the major components of the activation system.

Activation block diagram

Figure 10.1. Activation block diagram

When a client receives a stub for an activatable server, the stub contains a special form of RemoteRefwhich initially contains a null “real” RemoteRefand an ActivationID for the remote object. When the stub is first used for a remote method invocation the RemoteRefis null, so the stub engages in a protocol interaction with the activation system daemon rmid in the remote host.[1] The result of this protocol interaction is a live RemoteRefwhich the stub can then use to invoke the remote method.

Behind the scenes, the activation system has taken the following steps:

  1. looked up the ActivationID

  2. found the ActivationGroup associated with it

  3. activated the group if necessary

  4. told the group to activate the activatable server if necessary

  5. obtained the activatable server's RemoteReffrom the group, and returned it to the client stub.

If any of these steps fails, an ActivateFailedException is thrown to the client.

Writing an activatable server

As we saw when discussing unicast servers in §7.3, there are essentially three ways to write a server using the Activatable class:

  • extend Activatable

  • extend RemoteServer or RemoteObject

  • extend some other class, or no class (i.e. implicitly extend java.lang.Object).

The discussions in §7.3 and §7.4 apply equally to activatable servers, with the exception that an activatable server must export itself on construction. In addition, the following extra steps are required when defining an activatable server:

  1. Define a constructor of a required form in the server class.

  2. Have this constructor export the object, by calling the appropriate base-class constructor or exportObject method.

  3. Register an activation group, or reuse an already registered one.

  4. Register the activatable server.

  5. Compile the activatable server.

These steps are discussed in detail below.

Define the required constructor

An activatable server must provide a public constructor of the form

ActivatableXXX(ActivationID id,MarshalledObject data)

where ActivatableXXX should be replaced by the name of the class being constructed. This constructor is used by the activation system to construct the server on demand.

This constructor is required to do one of two things, depending on whether or not the server is derived from Activatable. These two possibilities are discussed separately below.

Extend the Activatable class

If the activatable server we are writing is derived from Activatable, the constructor described above (the “Activation” constructor) must call one of the following constructors for its Activatable base class:

Activatable(ActivationID id, int port)
Activatable(ActivationID id, int port,
       RMIClientSocketFactory csf, RMIServerSocketFactory ssf)

depending on whether it does or does not want to specify client and server socket factories. The call will be via one of the forms:

super(id, port);
super(id, port, csf, ssf);  // csf/ssf are the client & server socket factories

By the rules of Java, if the server we are writing extends Activatable directly, this invocation will be in the server class itself; otherwise it will be in that class in the server's inheritance chain which does extend Activatable directly.

Extend another class

If the server we are writing is not derived from Activatable, the constructor we have just described (the “activation” constructor) must call—directly or indirectly—one of the following methods:

Activatable.exportObject(Remote remote,ActivationID id,int port)
Activatable.exportObject(
     Remote remote,
     ActivationID id,
     int port,
     RMIClientSocketFactory csf,
     RMIServerSocketFactory ssf)

depending, again, on whether it does or does not want to specify client and server socket factories. These methods are public and static in Activatable and so are accessible to all classes.

Unlike the export step for UnicastRemoteObject, which can be deferred, the export step for Activatables must be complete when the constructor exits.

An activatable server can extend RemoteServer or RemoteObject. In this case, the server inherits remote object semantics from RemoteObject. Its behaviour under cloning and non-RMI serialization is up to you. Other than inheriting remote object semantics and various public static methods, such a server is identical to a server which extends a class other than Activatable, RemoteServer, and RemoteObject.

As RemoteServer only exports static methods, there is little to choose between extending RemoteServer or RemoteObject.

Registration

Registration is the process of making an activatable server known to the activation system as an entity which can be created and activated on demand.

This should not be confused with the functions of the RMI registry, which provides a name binding/lookup service.

The process of registration is rather complex. This is mainly because of the complications added by activation groups and initialization arguments. Further reasons are discussed in §10.15.

The basic registration steps are illustrated in Example 10.1.

Example 10.1. Registering an activatable server

String file  = ...;            // URL of your security policy file
String location = ...;         // Codebase URL
MarshalledObject  data = ...;  // initialization argument for activatable
Properties props = new Properties();
props.put("java.security.policy",file);
// At this point you may set other system properties for the group
ActivationGroupDesc.CommandEnvironmentace = null;
ActivationGroupDesc groupDesc = new ActivationGroupDesc(props,ace);
ActivationGroupID gid =
       ActivationGroup.getSystem().registerGroup(groupDesc);
ActivationDesc desc = new ActivationDesc
                  (gid,MyActivatable.getName(),location,data);
MyRemote rx = (MyRemote)Activatable.register(desc);

In this example:

  • MyRemote is the name of a remote interface

  • MyActivatable is the name of an activatable class which implements the remote interface

  • initialization of the variables file, location, and data is up to you

  • data may be null.

These registration steps are discussed in detail below.

Registering an activation group

An activatable server is registered in an activation group, so we must first consider registration of activation groups.

To register an activation group, create an ActivationGroupDesc, using one of its public constructors, and register it using ActivationSystem.registerGroup. This returns an ActivationGroupID which you then supply to the object registration method discussed below.

Let's consider the process step by step.

  1. Construct an instance of Properties, in which you should specify the security manager settings, including the absolute location of the security policy file for the group.

  2. Construct an instance of ActivationGroupDesc.CommandEnvironment—usually null, unless you want to use a non-standard path or options for the java command executed when the group is activated.

  3. Construct an ActivationGroupDesc from these two items.

  4. Register this group and obtains its group ID. This returns an ActivationGroupID, which you can subsequently use to register objects within the group, and to unregister the group.

  5. Save the group ID. This group ID is a precious thing. If you don't want to keep creating groups ad infinitum, you should save the group ID somehow—typically in a file—via serialization.

    Sun's activation tutorials used to state that you should now explicitly create the group in the current JVM by calling ActivationGroup.createGroup. This is unnecessary and undesirable: instead, just use the constructor for ActivationDesc that takes a groupID parameter. See the discussion in §10.15.2.

Registering an activatable server

The process of registering an activatable server is the same whether or not the object is derived from Activatable.

To register an activatable server, you need an activation descriptor (ActivationDesc); to create an ActivationDesc you need the group identifier (an ActivationGroupID) obtained in the previous step, and the activatable server's class and initial data if any.

  1. Create an activation descriptor (an ActivationDesc), specifying the activation group ID;[2] the object's class name as a String, including package qualifiers—typically the result of Class.getName; a location—a URL from whence the class definition can be loaded when the object is activated; and either a null or a MarshalledObject containing initial data for the object.

  2. Register this activation descriptor. The result of this method is an object of type Remote: it is a remote reference—a remote stub for the activatable erver—which you can use in the same way as the result of a registry lookup.[3]

  3. Save the remote reference. Like the activation group ID, this remote reference is also a precious thing.

You can save it in a file (via serialization), or in a persistent naming service if one is available.

You must ensure that the reference is serialized somewhere, possibly by a client, otherwise the registration is effectively lost. Registration gave you a persistent remote reference, but you must make it persist somewhere, otherwise the whole exercise has been pointless.

The activation system lacks lookup and list methods for group IDs, activation IDs, and remote references to activatable servers; otherwise it would be possible to use the activation system's own database rather than have to save groupIDs and activatable references yourself. See also §10.12.1.

The saved reference can be retrieved and used, behaving as a “faulting” reference to the activatable server. The saved reference remains valid after system reboots, and on different host computers connected to the same network.

You will probably also bind the reference to a name in the RMI registry: perhaps immediately, to make the activatable server immediately available to clients; or you can arrange a registry initialization program to “prime” the registry each time it starts up, using serialized remote references saved as described above. You could also use the persistent registry technique discussed in the Exercises of Chapter 6.

The activation system provides two other means of registering activatable servers: during construction and during export. These are briefly discussed in §10.15.

It's rather difficult to unregister an activatable server. The Activatable.getID method has protected member access, so only the activatable object can unregister itself, unless you add a public accessor method for the ID to your activatable server. In the case of an activatable server not derived from Activatable, you must also save the activation ID provided on construction, so that this accessor can return it.

A registration is a singleton

The result of a single registration is a “singleton” server. Only one instance of the server will be activated, regardless of the number of client connections. If that's not what you want, you should review whether the server in question needs to be activatable. See the discussion in §12.10. Alternatively, you should register the server multiple times and arrange to distribute the resulting stubs according to your requirements, e.g. to a load-balancing scheme.

Registrations are persistent

The result of a single registration is persistent across invocations of rmid, even if you lose the activation group ID and activation ID. There is no garbage-collection of these items—the registrations are held in rmid's database and will remain as long as the database exists.

Building an activatable server

This process is no different from the process of compiling a non-activatable server, described in §7.7.

Run-time setup

The only run-time setup required for activatable servers is to ensure that the activation daemon rmid is running, and perhaps to bind the activatable stub(s) into the RMI registry. You can accomplish the latter by a variant of the registry load program described in Chapter 6.

Codebase and activation

You must specify a codebase at least once, perhaps twice, when setting up activatable servers:

  • when registering activatable servers with the activation system, so that it can create instances of activatable servers

  • when binding an activatable server into the registry, if you use this technique, so that the registry will locate the stub classes correctly.

These actions occur at different phases of execution, so the codebase may have to be specified twice.

rmid security policy—JDK 1.3

Activatable RMI systems which worked under JDK 1.2.2 do not work unchanged under JDK 1.3. Lurking deep in the “Summary of New Features and Enhancements” for JDK 1.3 is the harmless-looking statement “rmid now requires a security policy file”.

This change was introduced because the ActivationGroupDesc structure provides the ability to register and activate an arbitrary executable, not just a Java program. Obviously this constitutes a security hole. Prior to JDK 1.3 (actually prior to JDK 1.2.2_006), this was addressed by the restriction that activatables can only be registered from programs running in the same host as the activation daemon, and the assumption that unprivileged code is unable to connect to port 1098. A stronger and more fine-grained security model was required.

To satisfy the new activation security semantics from JDK 1.3 onwards, you must specify one of the following in the command line for rmid:

  • no security, by starting rmid with the command-line argument -J-Dsun.rmi.activation.execPolicy = none; this replicates the JDK 1.2 behaviour (not recommended, except for temporary development situations)

  • a security policy file, by starting rmid with the command-line argument -J-Djava.security.policy = file, where file is the name of an rmid policy file as described in the JDK documentation for rmid

  • an alternate security policy, by starting rmid with the command-line argument -J-Dsun.rmi.activation.execPolicy = classname, where class-name is the name of an alternate rmid policy class as described in the JDK documentation for rmid.

If you don't specify one of the above security solutions to rmid, or if the security solution doesn't grant all the required permissions, attempts to use activatable stubs in clients will fail with the exception java.security.AccessControlException for a missing ExecPermission or ExecOptionPermission.

Note that AccessControlException extends SecurityException which in turn extends RuntimeException, so this exception will only be caught if there is a handler in the client for one of those exceptions.

During development, specifying an activation execPolicy of none may be used as a stopgap. In production, you normally would supply an rmid policy file. This must contain entries granting ExecPermissions for all the executables used by the activation daemon, normally just java (and perhaps java_g during development), and ExecOptionPermissions for all the system properties you have specified when defining activation groups, including the java.security.policy file for the group.

The rmid security policy file of Example 10.2 can be used as a starting point.

Example 10.2. Activation security policy file

// Security policy file for rmid (activation daemon)
grant {
      // permission to execute the specified program(s)
      permission com.sun.rmi.rmid.ExecPermission
           "d:\jdk1.3\bin\java";     // adjust to suit your installation
      permission com.sun.rmi.rmid.ExecPermission
           "d:\jdk1.3\bin\java_g";  // adjust to suit your installation
      // permission to set the specified file as the security policy file for the group
      permission com.sun.rmi.rmid.ExecOptionPermission
           "-Djava.security.policy=d:\projects\RMIBook\rmidgroup.policy";
      // permission to set the following properties
      permission com.sun.rmi.rmid.ExecOptionPermission
           "-Djava.security.debug=*";
      permission com.sun.rmi.rmid.ExecOptionPermission
           "-Djava.rmi.*";
      permission com.sun.rmi.rmid.ExecOptionPermission
           "-Dsun.rmi.*";
};

The file supports a wild-card syntax as shown. Sadly, the Java policytool doesn't yet know about ExecPermission and ExecOptionPermission, but you can type in the permission names yourself, so you can still use this tool to manage the file. See the JDK documentation for rmid for further information.

Activation and the Unreferenced interface

An activatable remote object may implement the Unreferenced interface. This is a reasonable and recommendable thing for activatable remote objects to do.

In §7.6 we saw that the Unreferenced.unreferenced method is invoked by the RMI system whenever the number of remote clients of a remote object falls to zero. We saw that the callback can occur when remote clients still exist. We also saw that for “unicast” remote objects, it is quite dangerous to use this opportunity to unexport the object, because this causes any future uses of current remote references to it to fail with a NoSuchObjectException in the client.

However, if the remote object is activatable, this difficulty disappears. All remote references to such remote objects remain valid and usable until the object is actually unregistered from the activation system.

When an activatable object receives an unreferenced callback, it is perfectly in order to de-activate the object. This implements an “exit when idle” strategy:

  • the remote object will be activated when it acquires its first client

  • it will remain in existence while it has remote clients

  • it will exit when the number of clients falls to zero

  • it will be recreated automatically if the number of clients increases beyond zero again.

If on the other hand you never unexport the remote object, it will never exit while the activation system (i.e. rmid) remains running. Both of these strategies are reasonable: which of them you want is up to you.

You should call Activatable.inactive rather than Activatable.unexportObject. The inactive method first unexports the object if necessary, then tells the activation system that the object is inactive; i.e. that if further references to it are used, it needs to be reactivated first. Don't just unexport the object yourself without telling the activation system.

The unexport/inactivation process also clears any local references to the object held by the RMI system: as soon as all other local references held by the application code are released the object can be garbage-collected.

The return value of inactive is true if the object could be unexported successfully or was already unexported, otherwise it is false. This is similar to the return value of the various unexportObject methods.

An implementation of the “exit when idle” strategy is shown in Example 10.3.

Note that the object is not actually garbage-collected until the JVM's garbage collector decides to do so, which may be never, and which may vary from platform to platform, JDK to JDK, and JVM to JVM. You can help things along by calling System.gc and System.runFinalization in the unreferenced method, but this doesn't guarantee anything. On the other hand, the activation group itself exits when there are no more active activatables in it: this causes the entire JVM devoted to the group to exit. This is garbage-collection with a vengeance.

Example 10.3. Implementing "exit when idle" in activatable server

// Unreferenced interface method
// Strategy is "exit when idle"
public void   unreferenced()
{
       try
       {
              boolean     exiting = Activatable.inactive(getID());
              if (exiting)
                       RemoteServer.getLog().println("unreferenced and inactive");
       }
       catch (RemoteException e)
       {
              // If this fails for any reason,
              // we are either still active or already inactive ...
       }
}

Which servers should be activatable

As a general rule, most of your RMI servers should be transient, i.e. exported by UnicastRemoteObject.exportObject. The criterion for choosing which servers should be activatable is often the same as for choosing which servers are bound into the registry: the “outermost” servers, the ones which clients will encounter first.

Remember, “activatable” implies “persistence” of the stub, and “persistent” and “transient” are opposites. The more transient your server, the less likely it is to be useful as an Activatable.

The activation system as an RMI registry

The activation system—the rmid program—contains a standard RMI registry running on port 1098. It is possible to use this as the registry for your entire RMI application: this saves you from running the RMI registry program. You can verify this for yourself by starting rmid, and then running the ListRegistry program of §6.11.1, with the command-line argument rmi://localhost:1098. You will see that the program succeeds, meaning that it has located a registry, and that the activation system has registered itself with the name “java.rmi.activation.ActivationSystem”.

In fact this is how ActivationGroup.getSystem works. Essentially, it returns the result of:

Naming.lookup("rmi://localhost:1098/java.rmi.activation.ActivationSystem")

cast to ActivationSystem, throwing an ActivationException if the activation system is not bound in the local registry at port 1098.

This implementation of ActivationGroup.getSystem is not mentioned in the RMI specification, although it is described in the JDK documentation. Other implementations may use a different technique.

Debugging

You may find it useful to run rmid with the system property sun.rmi.server.activation.debugExec set to true and monitor its output. This setting causes the activation system to log all attempts to activate groups and servers, and all exceptions arising from those attempts.

You may also find it useful to run rmid with -C-Djava.rmi.server.logCalls = true. The -C mechanism transmits the argument following to all activation-group processes started by rmid. In this case it enables remote call logging in all activation groups, which you probably want at all times.

Debugging utility

Sun has made an activation debugging utility available on a non-supported basis.[4] This utility is a tool to read and print the contents of an rmid log directory, i.e. the Activation database. The output is a list of all the registered activation groups and activatable servers, and a log of actions taken by rmid.

Activation groups in Win32

On Win32 platforms you might expect to see rmid, which runs in a command window, spawn other command windows to execute the JVMs of activation groups. This does not happen; instead, the command window of rmid contains the output of all the JVMs of all the active activation groups. Multiple JVMs are started as separate processes, but their inputs and outputs are all piped to the input and output of the rmid process, which appear in the rmid command window.

Activation clients

Clients of activatable servers are largely indistinguishable from clients of unicast remote object servers. The only differences are that they may encounter activation delays and activation exceptions.

Activation delays

Clients of activatable servers need to allow for time for activation before they think about timing-out. When a client invokes a remote method in an activatable server which is not currently running, the activation system at the server host must activate the server. This is generally pretty quick, as it's not much more than the instantiation of a Java object: the client generally doesn't need to be too aware of this issue.

However, if the activation group in which the server was registered isn't running, the group itself must be activated and then the server activated by the group. Activating a group involves the creation of a new process, which is a heavyweight activity by comparison with creating a Java object, especially if the host is heavily loaded.

Activation exceptions

An invocation of a remote method in an activatable server may throw an ActivationException. Now, you are already obliged to catch RemoteException by the signature of the remote method, and ActivationException extends RemoteException, so it is therefore perfectly possible not to catch it explicitly, as illustrated in Example 10.4.

Example 10.4. Simplistic exception-handling for activatable call

try
{
       myRemote.remoteMethod();
}
catch (RemoteException e)
{
      // some RMI exception caught
}

However, activation exceptions generally indicate a serious problem at the other end, and you should give careful consideration to catching them explicitly. In particular you should treat UnknownGroupException and UnknownObjectException, which both extend ActivationException, as extremely serious conditions. ActivateFailedException indicates that the object couldn't be activated for some reason, which may be transient; UnknownGroupException and UnknownObjectException indicates that the client is using an invalid activatable reference: one which doesn't refer to any known activatable service at the host. This is illustrated in Example 10.5.

Example 10.5. Improved exception handling for activatable call

try
{
       myRemote.remoteMethod();
}
catch (ActivationException e)
{
       // unknown group or object: permanent error with stub
}
catch (ActivateFailedException e)
{
       // some other activation problem, possibly transient
}
catch (RemoteException e)
{
      // some other general RMI problem
}

Remarks on the Activation Package

The java.rmi.activation package is the most complex part of the RMI specification. We have already discussed those parts of it which really constitute its external API and which are of practical use. The rest of it is of no practical interest to the programmer and can be ignored. The following discussion takes you “under the hood” of activation, for those who are interested.

How it really works

Activation is itself a set of remote services, built “on top of” RMI. Just like any other RMI application, it is built out of remote interfaces and implementations of remote services. Most of these are part of the internal design, not part of the activation API used by Java programmers (other than those implementing Activation systems).

Figure 10.2 shows all the components of the Activation system. In the diagram, single-ended arrows indicate RMI client/server relationships, with the arrow-head located at the server end.

Activation block diagram—detailed

Figure 10.2. Activation block diagram—detailed

You don't need to know much about this detailed version of the block diagram, or about most of the Activation package. The following notes discuss the remaining interfaces, classes, and methods. In general they are of no concern to RMI programmers unless they are implementing Activation themselves.

Creating the activation group

ActivationGroup.createGroup is called by the activation system. Calling it yourself is not generally appropriate. The setup programs in Sun's activation tutorial used to create a group, but only because they used the wrong constructor for ActivationDesc, the one which doesn't take a groupID parameter, but uses the default activation group—which must exist, otherwise an ActivationException is thrown.[5] Creating the group in the setup program makes no sense; using the wrong constructor and then working around its behaviour is the wrong solution. Use the constructor which does take an activation group ID.

Simultaneous registration and export

Activatable has constructors and exportObject methods which implement a simultaneous registration/export facility. Activatable servers can simultaneously register and export themselves, or be simultaneously registered and exported by other code. You must be running in an activation group, otherwise an ActivationException is thrown.

It is difficult to see the point of this feature. It is simpler to keep registration code—setup programs—separate from activatable code. No doubt there are times when you continually want to register new activatable servers, but consider the risk and costs of combinatorially exploding the number of activatable servers. If you need to register and export a server immediately, you can already do it yourself with the rest of the activation API.

For the record, the registration/export constructors and exportObject methods correspond closely to the various constructors of ActivationDesc, without the ActivationGroupID parameter.

The ActivationGroup class

All the non-static ActivationGroup methods—activeObject, inactiveGroup, inactiveObject, and newInstance—implement the ActivationInstantiator interface. Ignore them.

ActivationGroupDesc has a constructor with which you can specify an alternate implementation class for the associated ActivationGroup. Ignore it. “Rolling your own” implementation of ActivationGroup is impractical and unnecessary.

The ActivationGroupId and ActivationID classes

ActivationGroupID and ActivationID both have public constructors. Ignore them. These items are obtained, not constructed:

  • ActivationGroupIDs are obtained on registering the group

  • ActivationIDs are obtained in the “activation constructor”, or via Activatable.getID if the server is derived from Activatable; you can't construct ActivationIDs because you can neither create nor obtain an Activator.

Remote interfaces

ActivationInstantiator, ActivationMonitor, and Activator are remote interfaces implemented by ActivationGroup and two hidden internal classes respectively. Ignore them.

ActivationSystem exports quite a few methods. The only ones of interest are:

  • getActivationDesc and setActivationDesc

  • getActivationGroupDesc and setActivationGroupDesc

  • registerGroup and unregisterGroup

  • unregisterObject

The registerObject method looks interesting, but in fact it is not much use, as it doesn't return a remote stub: use Activatable.register instead.[6]

Exercises

1:

Modify the remote date/time server exercise of Chapter 7 to be activatable. Test the system and show the output.

2:

Modify this server to implement the “exit when idle” strategy.

3:

Modify this server to not implement the “exit when idle” strategy, but instead to be forced into existence each time rmid starts.

4:

Study §10.15. Write a public final class called Activation which exports static methods implementing all the methods in the Activation interface that a programmer really needs in practice. Exclude all constructors and methods of the classes Activatable, ActivationDesc, and ActivationGroupDesc, and all the exception classes.

5:

Modify the server created in the exercises above to use the class of the previous exercise rather than call the activation API directly. Re-test the system and show the output.

6:

Modify the “exit when idle” version of the activatable remote date/time server, to save its date of last inactivation by resetting its ActivationDesc, and to display this information when activated.



[1] To be specific, it calls ActivationID.active, a local method which calls the remote method Activator.activate in the target host's activation daemon, using a bootstrap technique similar to that used to contact the RMI registry.

[2] Do not omit the groupID—do not use the constructor for ActivationDesc which omits this parameter. Otherwise, you must do the ActivationGroup.createGroup step described above.

[3] Note this asymmetry: registering a group returns its ID, which can be used to register objects in it, or unregister the group; registering an activatable server returns a Remote, which can be used to activate it. In another asymmetry, Activatable.register returns a Remote, but ActivationSystem.registerObject returns an ActivationID. The former is called by users, the latter is called by the system. (See also the footnote for §10.15.6.)

[4] RMI Utilities (reg, rmipm), posting to the RMI Mailing List, 29 November 1999. It was also at http://developer.jini.org/exchange/users/aecolley/rmiutil, under the name rmipm.jar at the time of writing, but search for the mailing list item. You should also read the associated document. At the time of writing, you had to be a member of the Jini Sun Community Source Licence programme to access this URL. You can join this programme at no charge; see directions for joining elsewhere at the Jini developer site http://developer.jini.org.

[5] According to the implementation and the online JDK documentation. This disagrees with several statements in the RMI specification, §7.4.8. The behaviour described in the specification was implemented in beta releases of JDK 1.2, but was changed prior to the release of JDK 1.2FCS. This is probably the source of the confusion in the activation tutorial.

[6] This method calls ActivationSystem.registerObject and then constructs an activatable stub. If you prefer complication, you could use ActivationSystem.registerObject and then ActivationID.activate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.85.135