Once activated, the Reaction OSGi service can be used by any number of client OSGi bundles to provide full asynchronous programming support. However, there are various lifecycle considerations which must be taken into account when designing a client OSGi bundle. There are three lifecycle events which the client must observe which can be summarised by the methods provided by the example LifecycleHandler class shown in Listing 8.2.
The first lifecycle event is client startup. This should only occur once the OSGi client bundle has been started and it has been successfully bound to the Reaction service. In the example, the client startup method is used to start a repeating timer which will print a `liveness' message to the console every second.
The second lifecycle event is client teardown. This occurs when the client bundle is stopped and the Reaction service is still running. Teardown implies a clean shutdown of the client, with the client cancelling all outstanding transactions with the Reaction service. In the case of the example, this involves cancelling the repeating timer which was set up during startup.
The third potential lifecycle event is client abort. This occurs when the client bundle is still running, but the Reaction service is shut down. In normal operation this should not occur, but clients should make every attempt to clean up on receiving an abort condition. Note that when a client is aborted it is no longer able to access the Reaction service, so cleaning up is restricted to tidying up independent resources. This will typically include such things as closing open files, killing local threads and closing GUI windows.
The lifecycle event handler shown in Listing 8.2 needs to be wrapped in the standard OSGi activation API in order to integrate as an OSGi client of the Reaction service. An example of such a wrapper is shown in Listing 8.3 which implements the standard OSGi activator and service tracker interfaces. Note that the OSGi specification makes no guarantees about the thread context to be used when issuing bundle activator and service tracker callbacks, so all method calls have been made synchronised.
A full implementation of this OSGi Reaction client example is provided in the osgi examples package. A corresponding bundle definition file is also included in the root directory (as OsgiStartupExample.bnd) which may be used in conjunction with the bnd bundle creation tool.
As defined by the standard OSGi lifecycle, the first method to be called on starting a bundle is the bundle activator's start method. The implementation used by the example client activator is shown in Listing 8.4. In this case a new OSGi service tracker is created for the Reaction service, with the lifecycle wrapper being set up to receive notifications of status changes to the Reaction service. At this stage it is not known if the Reaction service is available, so it is not possible to call the lifecycle startup method.
Once the client bundle has been started, the OSGi framework will attempt to bind the client to a running instantiation of the Reaction service. If successful, this is notified using the service tracker's addingService callback method. The example used by the example lifecycle wrapper is shown in Listing 8.5. If a lifecycle handler is not already running, this method will create one and then invoke its startup method. By calling the startup method, the wrapper is indicating to the lifecycle handler than the client bundle has been correctly started and bound to a running Reaction service.
When a Reaction client is being shut down, the OSGi framework will call the bundle activator's stop method while the client is still bound to the Reaction service. This allows the client bundle to perform a clean shutdown - cancelling any outstanding transactions with the Reaction service. The way in which this is handled in the example lifecycle wrapper code is illustrated in Listing 8.6.
The final action of the activator's stop method is to close the Reaction service tracker. This will then cause the framework to issue a callback to the service tracker's removedService method, as shown in Listing 8.7. Since the lifecycle handler has already undergone a clean shutdown at this stage, no further action is usually required.
As previously discussed, an abortive shutdown occurs when the Reaction service is removed while the Reaction client is still running. This causes the OSGi framework to issue a removedService callback as shown in Listing 8.7 without previously having called the activator's stop method. The consequence of this is that an abortive shutdown will be detected, causing the lifecycle handler's abort method to be executed.