If you’ve ever had the strange feeling that someone is watching you, after this chapter you’ll have no doubt that it’s true. In this chapter we add a new feature to Toast that quietly tracks the vehicle’s location.
Like all the functionality we’ve added to Toast so far, the tracking code is pluggable. But unlike the prior scenarios, this one is headless; that is, it has no user interface. We wouldn’t want you to think that the only way to add functionality to Toast is via an icon on the user interface.
Most important, the tracking scenario gives us the opportunity to demonstrate OSGi’s support for dynamic configuration to change how the tracking scenario operates on the fly.
In this chapter you will learn
• How to build a headless tracking application that reports to the back end
• How to use OSGi’s ConfigurationAdmin
service to control the frequency of reports to the back end
• How to run Toast with the new tracking application
Trucking companies, car rental agencies, and especially parents of teenagers are very interested to know the location of their vehicles. The Toast tracking scenario wakes up every ten seconds, fetches the vehicle location from the IGps
service, and then uses the IChannel
service to send the readings to the back end. Figure 12-1 shows how the TrackingMonitor
and TrackingServlet
fit into the client and back end architecture.
The tracking scenario consists of one bundle for the client, one for the back end, and one core bundle that is used on both the client and the back end. The details of the tracking functionality are not particularly interesting here, so we will do a quick tour of the setup and then look at configuration issues.
Since the core bundle is required by both the client and the back end, we can avoid compilation errors by loading it first:
• Use the Samples Manager to load the bundle org.equinoxosgi.toast.core.tracking
into your workspace.
As in the emergency scenario, this bundle defines some constants in ITrackingConstants
that are used by both the client and the back end. These constants are used throughout the chapter and are shown here for reference:
The back end portion of the scenario uses a servlet to listen for vehicle location messages from the client. For now, the back end just logs the information to the console.
• Load the org.equinoxosgi.toast.backend.tracking
bundle into your workspace using the Samples Manager.
The structure of this bundle is similar to the back end portion of the emergency scenario in the org.equinoxosgi.toast.backend.emergency
bundle. From its component.xml
file, shown in the following snippet, you can see that it provides no services and references only the HttpService
. This is an immediate DS component that is activated upon acquiring the HttpService
.
The Component
class provides the implementation with startup
and shutdown
methods for activation and deactivation. Upon activation, the Component
instantiates the TrackingServlet
and registers it with the HttpService
. Recall that the rationale for using a separate Component
class as opposed to using the TrackingServlet
as the component’s implementation is based on the desire to keep the TrackingServlet
as a pure HttpServlet
. This way the Component
class deals with the URL and the servlet alias that servlets should not know about. This is nearly identical to the EmergencyServlet
shown in Section 7.1.2, “The Back End Emergency Bundle,” so it is not shown here.
Let’s move on to the client side, where things get more interesting. Here we need a TrackingMonitor
to poll the GPS every ten seconds and report the vehicle location to the back end via the IChannel
service:
• Copy the org.equinoxosgi.toast.client.tracking
bundle into your workspace using the Samples Manager.
The component.xml
reveals that this component references the IGps
and IChannel
services. You can also see the usual startup
and shutdown
methods that handle component activation and deactivation. But this time, there are two new entries in the component. These are highlighted in the following snippet:
At the end of the code, notice that there is a new <property>
element that defines a property called delay
with a default value of 10
. This property determines the number of seconds the client should delay between sending tracking updates to the back end. Later on in this chapter we will dynamically configure the tracking component by changing this property.
The other thing to notice is that the <component>
element now has its modified
attribute set to delayChanged
. This is the name of the component method that DS invokes when the component’s properties change. Later, you’ll see how this plays out. In the meantime, take a look at TrackingMonitor
’s startup
and updateDelay
methods, shown in this snippet:
DS invokes the startup
method with a Map
of properties as an argument. This Map
includes an entry for each property defined in the component. In this case, the Map
contains just an entry for delay
with a default value of 10
. In the private updateDelay
method, the TrackingMonitor
gets the delay
property from the Map
and sets its delay
field to this value. The startup
method then starts a Job
that sends a tracking message to the back end. It then uses the value of the delay
field to determine how long to wait before repeating the Job
.
Let’s checkpoint our progress by running Toast with the basic tracking scenario installed. The dynamic configuration is not happening yet, but it’s worth seeing that the tracking runs without it for now. Follow these steps to update the two product files:
• Add both the org.equinoxosgi.toast.core.tracking
and org.equinoxosgi.toast.backend.tracking
bundles to the backend.product
.
• Add both the org.equinoxosgi.toast.core.tracking
and org.equinoxosgi.toast.client.tracking
bundles to the client.product
.
• Now run the back end and the client. Watch the console to see that the client is reporting its location to the back end every ten seconds.
With the basic tracking scenario in place, we turn our attention to dynamic configuration.
OSGi’s ConfigurationAdmin
service provides a mechanism for programmatically configuring component properties. Specifically, it means we can use it to change the TrackingMonitor
’s delay property at runtime. ConfigurationAdmin
does not provide a user interface but rather a set of APIs that our code can invoke to change the properties.
Since OSGi’s ConfigurationAdmin
service provides the capability for the delay
property to be dynamically changed at runtime, we need a way to surface this to the user. The simplest way is to use a web interface based on the trusty HttpService
. We’ll implement a servlet that serves up a web page that allows the user to change the tracking delay. This servlet uses the ConfigurationAdmin
APIs to push the update to the TrackingMonitor
. Figure 12-2 shows the modifications to the client side of Toast to support dynamic configuration.
• Use the Samples Manager to load the org.equinoxosgi.toast.client.tracking.config
bundle.
The plumbing on this bundle is very similar to that of the back end emergency and tracking bundles. When the org.equinoxosgi.toast.client.tracking.config
component is activated, the Component
class’s startup
method registers the TrackingConfigServlet
with the HttpService
. A simplified version of the servlet’s doGet
method is shown in this snippet:
When an HTTP request comes in from the web browser to change the delay, the new value for the delay is parsed from the request parameter and passed to the private updateDelay
method shown here:
The servlet’s updateDelay
method uses the ConfigurationAdmin
service to look up the Configuration
for the tracking component using its PID and its bundle’s location.
The component’s PID is the unique persistent ID that ConfigurationAdmin
uses to persistently store its Configuration
. When configuring a DS component, the PID is the component’s name as specified by its <component>
element’s name
attribute.
The bundle location is used by ConfigurationAdmin
as a rather weak, and optional, security feature that helps ensure that while all bundles can modify their own configuration data, only privileged bundles can modify another bundle’s configuration data. Passing null
as the location parameter bypasses the security check, which is exactly what we are doing here.
The updateDelay
method gets the properties Dictionary
from the Configuration
, creating a new one if one does not exist. Then it puts the new delay value into the properties and calls the ConfigurationAdmin
service’s update
API, which in turn updates the tracking component.
Because of its close integration with ConfigurationAdmin
, DS is notified when a Configuration
has been updated. DS then invokes the delayChanged
method on the TrackingMonitor
, passing in a Map
of changed properties. Remember that the delayChanged
method is the org.equinoxosgi.toast.client.tracking
component’s modified
method. This method is called when the component’s properties have been modified, so long as its configuration remains satisfied and it is activated.
Here the delayChanged
method fetches the new value for the delay
property and restarts the Job
so the new value can take effect.
If we had chosen not to set the org.equinoxosgi.toast.client.tracking <component>
element’s modified
attribute, DS would instead have deactivated and reactivated the component. In our case, this would not make a noticeable difference, but if other components were dependent upon ours, the deactivation/reactivation would percolate all the way up the dependency chain. In some cases, this might have some undesirable side effects, such as the disappearance and reappearance of screen icons.
With a slight modification to the client product, we can run Toast with configurable tracking:
• Add the bundles org.eclipse.equinox.cm
, Equinox’s implementation of the ConfigurationAdmin
service, and org.equinoxosgi.toast.client.tracking.config
to the client.product
.
• Run the back end and the client. Again, watch the console to see that the client is reporting its location to the back end every ten seconds.
• Now point your web browser at the following URL: http://localhost:8081/client/tracking-config.
Figure 12-3 shows the web interface provided by the TrackingConfigServlet
. Try clicking on the links to change the delay between tracking messages.
Each time you change the property from the web browser, the ConfigurationAdmin
service persists the value. But if you run the client again by clicking the Run button in the client.product
, the tooling clears the local storage, effectively resetting the tracking delay to its default value of ten seconds.
There is a way to run the client again without resetting local storage. If you select Run > RunConfigurations..., you will find a launch configuration under Eclipse Application called client.product
. This launch configuration is created automatically when you click the Run button in the client.product
. Ensure that the Clear the configuration area before launching option on the Configuration tab is unchecked, to leave the persistent storage from the previous run intact—the tracking delay should be unchanged from the previous run.
This chapter showcases OSGi’s ConfigurationAdmin
service as the mechanism for managing the configuration of available services. We walked you through adding a vehicle-tracking mechanism to Toast. ConfigurationAdmin
was used to manage the frequency of location updates. The implementation follows the same client and back end pattern as the emergency scenario and presents a simple web UI for adjusting the tracking frequency.
ConfigurationAdmin
makes it easy to define properties in a component, update them dynamically, and persist them between runs. Tracking is only one small example of how ConfigurationAdmin
can be used for dynamic configuration. Chapter 15, “Declarative Services,” goes into more detail on the other capabilities and uses for ConfigurationAdmin
.