[Up: Reference Implementation]
[Previous: Object Key Generation] [Next: Collocation]
Transient objects require that object references to objects in a particular server become invalid if that server is shut down. In other words, the object keys for transient objects must be unique to a server instance.
This is guaranteed by the composition of the GUID that is used as a prefix for the object key, which, as seen above, contains the host name, the server process' PID and a timestamp. Together, these three components uniquely identify a server. If two instances of the same server are running on the same host simultaneously, the PID is different, and if a server is shut down and run again, at least the timestamp (with millisecond resolution) differs. The GUID therefore serves a dual use as adapter identifier and transient property.
For persistent servers, a different GUID must be used that is reusable across server instances, but as the POA specification ignores the administrative issues of persistent objects, the how of assigning such GUIDs is undefined.
As a solution for the MICO POA, the user must use the -POAImplName option on the command line to set an Implementation Name when starting a server that implements persistent objects - otherwise, the Invalid Policy exception is thrown when trying to create a POA with the persistent lifespan policy. This identifier is then used as adapter identifier in the object key. It is the user's responsibility for keeping the Implementation Name unique.
Transient objects allow for direct communication between client and server: if the server's transport end point is disconnected as a result of server shutdown, all the client's object references into that server become invalid, and no further communication is possible.
Persistent objects, however, require a mediator  that intercepts requests while the server is off-line, starts up the server on demand, and forwards the request when the server is again ready to receive them . As mentioned in section 4.2.4, this issue is ignored by the POA specification and must be solved by the vendor.
For this implementation, it was decided to re-use the already available component of the ``BOA Daemon,'' which already did much of the same work for the MICO BOA. The BOA Daemon manages the Implementation Repository, which contains information about available servers and the objects they implement.
The BOA Daemon contains the ``OAMediator'' singleton object, and cooperates with the BOA to
This is a problem in the server, where object references are generated as part of object activation. In the OAMediator design, the BOA does not generate object references on its own, but invokes the OAMediator, which uses the object key provided by the BOA and its own profiles to produce a new object's reference pointing to the OAMediator.
After object activation, OAMediator and BOA follow an elaborate protocol which is described in section 5.4 of , where it is referred to using its historical and still accurate name ``BOA Mediator.''
However, the existing OAMediator did not prove sufficient for persistent objects realized through a POA. It did not provide persistent storage, and it required the registration of all persistent objects. This would have been a real constraint when taking into account the concept of virtual objects, and objects realized through a default servant. While such objects do not require resources on the server side, they would then require an entry in the OAMediator's tables without ever being able to clean them up.
Rather than extending the OAMediator, it proved easier to introduce a new ``POA Mediator.'' Though it serves much the same purpose, it was implemented with less code than the original by using a new design and the GIOP location forwarding mechanism, which hadn't been available to the OAMediator.
GIOP location forwarding allows to update a client's object reference with new profiles and conveniently matches our mediator's requirements. After starting a new server, the mediator returns a forward message to the client, which - transparently to the user code - resends the request to the new location. Further requests are sent directly to the server and do not need handling by the mediator, until the server is shut down. This is noticed by the client, which receives a GIOP Close Connection message and then falls back to contacting the mediator again. The communication overhead induced by the mediator is kept minimal.
The POA Mediator is also a singleton object, integrated in the ``BOA Daemon.'' True to the idea of a microkernel ORB, it is plugged into the ORB as an object adapter: instead of delivering requests to a local implementation, they are forwarded to the currently running server. Figure 5.6 shows the architecture of the POA Mediator. The numbered arrows indicate a request's path to the server:
Information about available servers is kept in the Implementation Repository, which has been extended with the new, according to BOA terms, poa activation policy. The Implementation Repository is now shared, and the two mediators must agree on the ``ownership'' of entries: the POA Mediator only handles servers with the poa activation policy, and a new rule has been added to the OAMediator to ignore such entries.
The POA Mediator must arrange to intercept all client-server communication. All object references to persistent objects must point to the mediator, so that the server can exit without invalidating any addresses. Rather than asking the mediator each time, a server and the POA Mediator exchange their object reference templates (see section 5.3) upon startup, when the server calls the POA Mediator's create_impl method. When creating an object reference in a POA with the persistent lifespan policy, the POA does not use the local ORB's template, but the POA Mediator's: requests will then be sent to the mediator first.
The mediator then uses the server's template to construct a forwarding address for incoming requests, by constructing a new object reference from the server's template and the request's object key.
But before that can be done, the correct implementation must be found. The POA Mediator may be managing many implementations simultaneously and needs a means of directing the request to the right one. The trick is to require that a server's Implementation Name must match the name of the corresponding entry in the Implementation Repository. When a server is started on demand by the POA Mediator, the necessary -POAImplName command line switch is added automatically. Because of the way an object key is constructed, this results in the object key being prefixed by the Implementation Name. All the POA Mediator has to do is to read the object key from the request, and to use its prefix as an index into the Implementation Repository.
The only information kept by the POA Mediator is a single table, keeping the object reference templates of currently active servers. By puzzling with the pieces of an object reference, costly communication with the server is avoided. Where the OAMediator had to be informed of object activation by the BOA, keeping a table associating them with both an Implementation Repository entry and an active server, the POA Mediator simply does not need to know.
Still, some minor handshaking between a server and the POA Mediator is necessary. The four possible states an implementation can enter are shown in figure 5.8.
If no server is running, the implementation is inactive. If a new request is delivered to the mediator, it consults the Implementation Repository to find the name of an executable file for the implementation (as deduced from the object key), and uses POSIX process mechanisms to start the new server and POSIX signals to monitor them. The act of starting the server transitions the implementation to the started state, in which the mediator does not deliver any requests but keeps them in a queue and waits for the server to announce its readiness.
Within that state, the server can perform initialization unhindered by incoming requests. The Root POA calls the mediator to exchange object reference templates and to restore its state information (see next section), and then allows the user to activate or restore objects.
If the user is finished setting up the server, the Root POA's POA Manager is transitioned to the active state. At that time, the POA Mediator is informed that the server is ready, by invoking its activate_impl method.
Having waited for that callback, the POA Mediator sets the implementation's state to active and begins request delivery, first by draining its queue and then by forwarding requests as soon as they come in.
This continues until the server shuts itself down by calling the ORB's shutdown method, either as the result of a method invocation with the intended side-effect of server shutdown, or of a timeout within the server, which could decide to stop itself after a period of inactivity. Ultimately, this causes the Root POA to be destroyed, which calls the mediator's deactivate_impl method and returns the implementation to the inactive state.
A race condition exists upon shutdown. Since the POA Mediator and the server run in parallel, requests may be delivered during the short time between the initiation of server shutdown and its unregistration with the POA Mediator, when the ORB still accepts requests after the implementation has been deactivated. Also, the server could have stopped processing requests some time before shutdown by setting its POA Managers to the holding or inactive state.
Requests for transient objects are simply failed: the object they're referring to is ceasing to exist. However, this is not true for persistent objects, and the server faces a dilemma:
Once the request is again received by the mediator, it determines the implementation to be in the inactive state and starts a new server. The old server may not have exited yet, so the old and the new server may run in parallel, but all requests are now directed to the new server.
Object state and their handling using servant managers has already been mentioned several times. However, not only persistent objects have state, but also persistent POAs themselves. If a POA has the ``system id'' id assignment policy, it must generate unique Object Ids upon each activation. This duty must be fulfilled beyond the server's lifetime, so that newly activated objects do not get assigned ``old'' Object Ids, which would result in a conflict when delivering requests.
For Object Id generation, a POA uses a UniqueId helper class, which is capable of encapsulating the current Id in a string. When a persistent POA is destroyed, it saves its state, the last-generated Object Id, in a global map. The Root POA, as part of server initialization or shutdown, stores and restores this table in the POA Manager, using the save_state and restore_state methods (see the IDL in figure 5.7).
An alternative would be to generate a unique prefix for Object Ids based, for example, on a timestamp. However, this is not as trivial as it seems, because a persistent POA can be created, destroyed and recreated within a process: a simple timestamp is not sufficient. With the side effect of being able to use simple Object Ids (a running number), this way of requiring one additional once-in-a-lifetime communication with the POA Mediator seemed a good compromise.
As with the extensions for the Interoperable Naming Service, a solution to the persistency question has been implemented that does not require any vendor-specific source code incompatibilities. The generic source code presented in  will work and produce the expected results without changes.
The only necessary efforts beyond the POA specification are administrative, to run the BOA Daemon and to add an entry to the Implementation Repository.
As a side note, the Implementation Repository also allows for coarse-grained mobility of servers. If the command to start the server is replaced with a remote shell invocation, the next instance of the server will be run remotely - and the client will not notice.
But again, we run into a bootstrapping problem, this time on the server side. In order to create object references and to export them, for example by entering them in the Naming Service, the first instance of the server has to be started manually, using one of three options:
It is also possible for a persistent server to run without contacting an Implementation Repository, but then clients will experience a ``transient'' exception when they try to send a request while the server is down. A third possibility is to create an entry in the Implementation Repository that leaves the implementation's executable undefined. The POAMediator is then unable to start a new server on demand, but will queue requests until a new server comes online by administrative action - the equivalent of the BOA's persistent activation policy.
It has been mentioned that the BOA Daemon should run permanently. MICO actually allows the daemon to be stopped and restarted. Upon shutdown, all connected servers are stopped, too, and their state information is written to a disk file, so that the system can be restored when the daemon is started again. However, clients that send a request while the daemon is down will also receive an exception indicating temporary failure.
[Previous: Object Key Generation] [Next: Collocation]
[Up: Reference Implementation]