Chapter 15. Declarative Services

As we have seen, the OSGi service mechanism greatly improves modularity and flexibility. But the programmatic API for registering and acquiring services is often challenging, as are the complexities of managing dynamic services. OSGi Release 4 introduced the Declarative Services (DS) specification to address these issues.

In Chapter 6, “Dynamic Services,” we introduced DS, and the subsequent chapters have assumed their use throughout Toast. This chapter presents a deep dive into the capabilities and use of the DS mechanism. In particular, we

• Recap the Declarative Services model and programming techniques

• Identify common usage scenarios for Declarative Services

• Discuss how to launch and debug an OSGi application that uses Declarative Services

• Take a look at the PDE tooling for Declarative Services

15.1 The Declarative Services Model

Working with the OSGi service model using the programmatic APIs can be complex and error-prone. In an attempt to simplify their code, developers tend to make optimistic assumptions regarding the availability of services, resulting in runtime exceptions at one extreme and object retention issues at the other.

In large-scale scenarios, using the programmatic API to work with the service model can also result in premature class loading and object instantiation, contributing to delayed application startup and unnecessary memory consumption.

An alternative is to be lazy and declarative. Equinox has supported such techniques for some time through mechanisms such as extension points and delayed bundle activation. DS brings laziness to the OSGi service model and simultaneously makes it much easier for developers to work with services, increasing the quality, scalability, and startup performance of their applications.

When using DS, a bundle declares components that can reference and provide services. A component is declared by a bundle in an XML document that is processed at runtime by OSGi’s Service Component Runtime (SCR) to create a component instance. A bundle can have multiple XML documents, and each document can contain multiple component declarations.

It is interesting to note that DS implementations are add-on bundles to the OSGi framework; that is, DS capabilities can be added to any R4.1 framework implementation—there is no need to build it into the framework.

15.2 Common Scenarios

Let’s review some of the most common design scenarios and how they are implemented with DS. We’ll start with the simplest component and then move to more typical scenarios of providing services, referencing services, and both referencing and providing services. Finally, we discuss some advanced scenarios, namely, component factories and the Whiteboard Pattern.

15.2.1 The Simplest Component

The following snippet shows how to declare the simplest possible component, the DS equivalent of “Hello, World”:

image

A component XML document must be XML 1.0–compliant and must be UTF-8 encoded. Each component XML document must be added to the bundle’s Service-Component manifest header:

image

The value of this header is a comma-separated list of bundle-relative file name paths. The last segment of each path may include a wildcard, for example:

image

You must use only forward slashes as path separators. Backslashes are illegal, even if they are doubled up. If a file path does not refer to a component XML document, DS will log an error to the LogService, if available. The Service-Component header is ignored for fragment bundles, but a fragment bundle may contribute XML documents to its host. Clearly this is a case where using a wildcard in the file path is useful. The XML describes the component and the POJO class that implements its behavior. Storing component XML documents below the OSGi-INF folder is a reasonable choice but is not required.

As the component does not provide any services, DS instantiates and activates it immediately. The component’s implementation class can be any public class that has a public default constructor. The component’s implementation class should already be familiar to you:

image

The implementation class can hook into its component’s lifecycle by adding two methods as shown in the following snippet:

image

The symmetry of the component class’s activate and deactivate methods is important in that it reflects the lifecycle of a component. In this example the activate method is called immediately upon the component’s configuration being satisfied; then once the activate method has been called, the deactivate method is called when the component’s configuration is no longer satisfied, or when its hosting bundle stops. The concept of a component’s configuration being satisfied, or not, is discussed in Section 24.1.2 of Chapter 24, “Declarative Services Reference.”

Notice that the component’s implementation class is simply an Object—it does not have to extend or implement another type. DS discovers the component implementation class’s activate and deactivate methods using reflection. While activate and deactivate are the default method names, you can specify different methods by setting the <component> element’s activate and deactivate attributes. In this way DS adapts to work with your POJO class rather than the other way around. The tutorial chapters in Part II often do this, using the method names startup and shutdown, since they’re more POJO-friendly than activate and deactivate. The next section also includes an example of this.

15.2.2 Referencing Services

A component can reference services by specifying nested <reference> elements. A component that references other services is activated only when every reference is satisfied based on its policy and cardinality.

In the following example, the <reference> elements do not specify the policy and cardinality attributes. This implies that the default policy of static and the default cardinality of 1..1 should be used. As such, an IEmergencyMonitor service and an ICrustShell service must be available before the component’s configuration is satisfied and the component can be activated.

image

When a referenced service is available, DS binds it to the component’s implementation by calling the method named in the <reference> element’s bind attribute. Likewise, when a reference service becomes unavailable, DS unbinds it from the component’s implementation by calling the method named in the <reference> element’s unbind attribute.

Both the bind and unbind attributes are optional, and as this snippet shows, unbinding is often not necessary, such as when it involves simply setting a field to null. Specifying the unbind attribute is necessary only when there is real work to be done, such as removing a listener from the soon-to-be-unbound referenced service. Of course, specifying an unbind attribute can assist with debugging since it gives you a place to log a message or set a breakpoint and observe that the referenced service has been unbound.

When using the static policy, the bind method is always called before the component is activated, and the unbind method is always called after the component is deactivated.

Once the component’s configuration is satisfied, DS activates it by instantiating the EmergencyScreen implementation class and calling its startup method. When the component’s configuration is no longer satisfied, or when the bundle stops, DS deactivates the component by calling the EmergencyScreen’s shutdown method:

image

When referencing a service, a component can specify one of four cardinality values to describe how many referenced services are required and desired. Similarly, they can specify one of two policy values to describe how the component handles referenced service changes. While these combinations result in eight possible pairings, the two most common parings are

1..1 and staticIt is not a coincidence that these are the default attribute values and the pairing that you’ll use most often. With a cardinality of 1..1 and a static policy, the referenced service is bound before the component is activated, and the component is deactivated before the referenced service is unbound. Toast uses these values in all but a couple of cases.

0..n and dynamicThe 0..n cardinality implies that the referenced service is optional and multiple, so the dynamic policy makes sense—you don’t want the activated component to be deactivated before a referenced service is bound and the component reactivated. And you don’t want the activated component to be deactivated before one of the many referenced services is unbound and the component reactivated. Toast uses these values in the back end portal’s service action lookup component.

Again, since in our example the <reference> elements do not specify the policy and cardinality attributes, the defaults of static and 1..1 are used.

15.2.3 Providing Services

In addition to referencing OSGi services, DS components can provide services to the OSGi service registry. This is done by listing the provided services in the component’s XML document and having the component class implement each provided service. The following snippet shows an example from the GPS bundle:

image

Notice that the <provide> element is nested within the <service> element and that each element describes a single provided service. The component provides the IGps service, so the implementation class FakeGps must implement IGps, and DS will register the component object as an IGps service.

image

While a component can have only one implementation class, it can provide multiple services. To support this, the component class must implement each of the provided service interfaces, and each service must be described by a <provide> element. Note that the same component implementation instance will be registered for each provided service.

15.2.4 Referencing and Providing Services

It is common for a component to both reference and provide services. This is effectively a merge of the previous two scenarios. The component lifecycle ensures that a component’s services are provided only while its configuration is satisfied. By default a component’s implementation class is instantiated and the component activated on the first use of a provided service; that is, the component is lazily instantiated when it is referenced. The following snippet shows this in action:

image

The emergency component references the services IGps, IAirbag, and IChannel and provides the service IEmergencyMonitor, which is implemented by the component’s implementation class.

image

15.2.5 Immediate Components

In an OSGi application it is common for DS components to provide services. Such components are considered lazy, and DS delays the loading and instantiation of each component’s implementation class until one of its provided services is requested. The performance and scalability benefits that this brings are compelling reasons for using DS. But not all components can or want to be lazy.

Most applications include a few components whose implementation class must be eagerly loaded and instantiated. DS calls these immediate components. Immediate components often reside at the top of the food chain, while others need to perform initialization behavior before the first service request, or are independent of services altogether.

To request that DS treat a component as immediate, set the <component> element’s immediate attribute to true. DS will respect this request unless the component is a factory component; see Section 15.2.7, “Factory Components,” for more details. Setting the immediate attribute to false never affects the immediacy of a component.

The Toast component org.equinoxosgi.toast.swt.emergency is an example of an immediate component. Once the implementation class EmergencyScreen has been instantiated, it registers itself with the ICrustShell. Since this component does not provide any services, it must be immediate since there is no way for it to be activated otherwise.

The Toast component org.equinoxosgi.toast.backend.portal is another example of an immediate component. Once the implementation class Portal has been instantiated, it creates and registers an instance of the PortalServlet class as a servlet with the org.osgi.service.http.HttpService. This component’s only interaction is via HTTP, so being lazy is not an option.

Other examples of immediate components include those that wish to start a thread, add a listener to a referenced service, communicate with hardware or an external system, or simply need the chance to perform initialization behavior prior to the first request for a provided service.

Immediate components can present a performance and scalability risk to an application since they often cause other components to be activated, classes to be loaded, and objects to be created earlier than is absolutely necessary.

15.2.6 The Whiteboard Pattern

As an alternative to the traditional Observer Pattern, the Whiteboard Pattern1 has been proposed for use in OSGi applications. The Whiteboard Pattern is not inherently OSGi-specific and could be implemented without OSGi, but it does require a publish/subscribe mechanism through which interested parties are discovered. The OSGi service registry is perfect for this.

1. See www.osgi.org/wiki/uploads/Links/whiteboard.pdf.

With the Whiteboard Pattern, the event source bundle and the event listener bundles are completely decoupled via the OSGi service registry: An event listener expresses its interest in the event source by providing a service, and an event source then discovers the event listener services through which change events are dispatched.

In addition to the loose coupling of the event source and the event listeners, the virtues of the Whiteboard Pattern include a simplified implementation of both the event source and the event listeners. There is no need for the event source to maintain a list of event listeners, and each event listener needs no knowledge of the event source. The OSGi service registry takes care of this by maintaining the set of interested event listener services and notifying the event source when the services are changed.

An additional benefit is the reduced possibility of object retention caused by an event listener neglecting to unregister its interest in the event source; the OSGi framework guarantees that all services are automatically unregistered when the registering bundle stops. Poorly coded event sources can, however, still incorrectly retain references to uninterested event listeners.

Despite these improvements over the Listener Pattern, there are some disadvantages of the Whiteboard Pattern:

• The OSGi service registry consists of a single namespace, making the set of event listeners global.

• Without care the application can become unnecessarily coupled to the OSGi framework.

• Given the active nature of the service registry, applications with many listeners may not scale well.

Since event listeners are services and the OSGi service registry maintains a global, flat list of services, listeners will hear all events regardless of the source. Of course, this can be highly desirable, but it can also unnecessarily complicate system configuration.

Domain objects using the Whiteboard Pattern typically rely on the OSGi service registry to maintain the event listeners. This is counter to the POJO and dependency injection approach that we have used throughout this book. In particular, it inhibits reuse in non-OSGi scenarios and complicates testing.

Of course, this coupling can be avoided by introducing the notion of a lookup mechanism and then supplying a service-based implementation. This allows us to retain the benefits of the Whiteboard Pattern while allowing the code to run without the OSGi framework.

We saw an example of this in Chapter 13, “Web Portal,” where the back end Portal registers the PortalServlet that handles HTTP requests by dispatching to a matching IPortalAction. In this way the portal servlet is easily, and infinitely, extendable. Here we take a closer look at the setup, starting with the back end portal component:

image

The back end portal is an immediate DS component whose implementation class, Portal, creates the PortalServlet and registers it with the HttpService.

When the PortalServlet is created, it is given an IActionLookup service. The PortalServlet handles an HTTP request by locating an IPortalAction using its IActionLookup service and then executing it. The IActionLookup service has a getAction API that returns the IPortalAction object matching a specified ID. The code is roughly as follows:

image

This action lookup behavior is defined by the IActionLookup service and is completely independent of OSGi. To hook in OSGi services using the Whiteboard Pattern, we have a ServiceActionLookup class that implements the IActionLookup interface in terms of OSGi services using the Whiteboard Pattern. This action lookup service is then injected into the Portal and used to handle portal web requests. The next snippet shows the service-based action lookup mechanism. The code looks a little complex but is reasonably straightforward.

The PortalAction inner class is a wrapper for user-supplied actions to ensure that the real action services are not accessed until required. Given the lazy nature of DS components, this defers the instantiation of DS-supplied IPortalAction services. The rest of ServiceActionLookup implements a cache of PortalAction wrappers and the required getAction method.

image

image

image

Notice that the addAction method takes a ServiceReference argument rather than an IPortalAction. This is the key to delaying the loading and instantiation of each bound IPortalAction until it is needed by the PortalServlet to fulfill an HTTP action request.

To hook this into DS using the Whiteboard Pattern, we need a component with a <reference> element for the IPortalAction service and have it use the dynamic policy and the 0..n cardinality. This allows any number of IPortalAction services to be referenced by the component. As IPortalAction services are registered, the ServiceActionLookup is notified by DS calling addAction, which creates and caches a corresponding PortalAction that wraps the ServiceReference. As action services are unregistered, they are unbound from the ServiceActionLookup component via removeAction. The component XML required to describe this is shown in the following snippet:

image

The <reference> element for the IPortalAction service uses a cardinality of 0..n because many services are expected but none are required. In this case using a policy of dynamic makes sense since we do not want changes in the available IPortalAction services to affect the activation of the ServiceActionLookup component.

While this certainly requires more code and is not quite how you would write your POJO servlet, it is very reasonable when you are trying to make the set of portal actions extensible while decoupling your business logic from OSGi.

The following snippet shows how the tracking action is contributed to the portal using DS by providing an IPortalAction service:

image

The implementation of the tracking action is as follows:

image

15.2.7 Factory Components

So far we have discussed how to use DS to describe components that are statically and automatically created once their configuration has been satisfied. When components need to be created dynamically, or when multiple instances of a component are needed, a DS factory component should be used. A factory component implicitly provides an org.osgi.service.component.ComponentFactory service that is used by other bundles and components to create and dispose of instances of the component.

To help explain factory components, we show you how to declare an airbag factory component for Toast that allows multiple airbags of varying kinds that reside throughout the vehicle to be dynamically configured.

To keep things simple, the scenario presented here starts with the code in the Samples Manager for Chapter 6, “Dynamic Services,” and walks you through editing the org.equinoxosgi.toast.dev.airbag bundle to make its DS component a factory component. We then implement a second DS component that configures Toast using the factory-component-provided ComponentFactory service to create six distinct airbag components.

15.2.7.1 Updating the Airbag Domain Logic

While all cars have airbags hidden within the steering column and behind the front console, it’s common these days to also see curtain airbags. Let’s start by enhancing the Toast domain logic to support different kinds of airbags, mounted on the left and the right, throughout the vehicle.

image

The new APIs getKind, getOrientation, and getRow allow us to query the type of airbag we have and where it is mounted in the vehicle. The KIND_* and ORIENTATION_* constants are intended to be used to set the state of IAirbag instances. The PROPERTY_* constants will be used to parameterize the creation of IAirbag instances. The use of these constants will become clear as we proceed through the example.

Now that we’ve enhanced the IAirbag interface, it is necessary to update the FakeAirbag implementation. To support airbags of varying characteristics, we have added three fields (one each for kind, orientation, and row) and the methods to satisfy the new IAirbag interface APIs. We have also overridden the toString method to allow a FakeAirbag to describe itself appropriately on the console or the log. Besides these domain logic changes, the most important changes are to the FakeAirbag’s startup method:

image

Remember, the startup method is the component’s activation method. The declaration of the startup method has been changed to take a Map argument, which is called by DS at runtime when the component’s configuration is satisfied and activated. At that time DS will pass in the FakeAirbag’s properties as created by the airbag factory component. This is discussed in the next section. The Map contains keys such as those defined by the IAirbag constants PROPERTY_KIND, PROPERTY_ORIENTATION, and PROPERTY_ROW.

15.2.7.2 Declaring a Factory Component

The existing airbag DS component needs to be updated to change it to a factory component. The <component> element has an optional factory attribute that is used to identify the component as a factory component.

When this attribute is set, DS ignores the <component> and instead registers a ComponentFactory service through which instances of the component can be manufactured. This is rather subtle and is one of the most confusing aspects of the DS component schema. When declaring a factory component, you can think of the <component> element as a blueprint for what the factory will manufacture.

image

While uniqueness is not required or enforced for the <component> element’s factory attribute, it is certainly recommended since this is used later by others that need to locate the ComponentFactory service in the OSGi service registry.

We have chosen to use the fully qualified IAirbag interface name as the component’s factory identifier. Not only does this uniquely identify the factory, but as the factory will be manufacturing components that provide an IAirbag service, it certainly appears to be intention-revealing.

We have also added a <property> element that defines the default value for the kind property of the airbag components that the factory manufactures. We’ll see shortly how this is used.

The factory component in this example happens to include a <service> element since it provides an IAirbag service. This is not a necessary part of being a factory component. It is perfectly legal for the components manufactured by a factory component to be immediate, providing no services of their own.

15.2.7.3 Registered Properties of a ComponentFactory Service

DS automatically registers a factory component’s ComponentFactory service with the following properties:

component.nameThe value of this property is defined by the <component> element’s name attribute, which in this example is org.equinoxosgi.toast.dev.airbag.

component.factoryThe value of this property is defined by the <component> element’s factory attribute, which in this case is org.equinoxosgi.toast.dev.airbag.IAirbag; this is the type of the service provided by the component.

Since there can be many registered ComponentFactory services, these properties serve to identify this particular ComponentFactory service, ideally uniquely. Bundles and components that wish to use a ComponentFactory service can use these properties to select the one they want.

15.2.7.4 Using a ComponentFactory Service

So far we’ve seen how to declare the airbag factory component, but we’ve still not seen how to use its provided ComponentFactory to dynamically create multiple parameterized airbag components. For this we need a new DS component that is responsible for using the ComponentFactory to configure the Toast airbag components—we call it the configurator for short. The configurator.xml file is as follows:

image

The first thing to notice about the configurator component is that it does not provide any services and is an explicitly immediate component. DS activates immediate components as soon as their configurations are satisfied, which for the configurator means once its referenced ComponentFactory service is available.

The configurator has two responsibilities: When activated, create Toast’s airbag components via the airbag ComponentFactory service, and when deactivated, dispose of the airbag components it previously created.

Since DS registers a distinct ComponentFactory service for each factory component it finds, the configurator component cannot use just any ComponentFactory! By specifying the <reference> element’s target attribute, it is able to select the ComponentFactory service with a component.factory property of org.equinoxosgi.toast.dev.airbag.IAirbag.

The configurator component’s implementation is the AirbagConfigurator class, which for simplicity resides in the org.equinoxosgi.toast.dev.airbag bundle—this gives the effect of the bundle configuring itself. Of course, this behavior could equally well reside in a separate bundle that is responsible for configuring all Toast components using all manner of ComponentFactory services.

Since the AirbagConfigurator class uses the OSGi-defined ComponentFactory interface, the bundle must import the package org.osgi.service.component.

image

image

The startup method is the component’s activation method. This method calls its private createComponent method six times to create six distinct airbag components. Each call to createComponent returns an OSGi-defined ComponentInstance object that represents an airbag component. These objects are cached in a field for later use.

The createComponent method is simply a helper that constructs a Dictionary and populates it with the properties to be passed to the ComponentFactory’s newInstance method. The newInstance method dynamically creates an airbag component, passing along instance-specific properties that DS delivers to the FakeAirbag’s startup method upon activation. These properties override any properties declared by the factory component’s XML, and since a kind property is declared in its XML, this property is therefore optional.

The AirbagConfigurator’s shutdown method, which is the component’s deactivation method, does the reverse of the startup method: It iterates through the list of components, calling dispose on each ComponentInstance. The dispose method causes DS to deactivate the airbag component represented by the ComponentInstance and call the FakeAirbag’s shutdown method. Finally, the AirbagConfigurator’s shutdown method sets the components field to null, which while not strictly necessary allows the method to preserve symmetry with the startup method.

15.2.7.5 Launching Toast

When the org.equinoxosgi.toast.dev.airbag.configurator component is activated, it creates six airbag components using the ComponentFactory service provided by the org.equinoxosgi.toast.dev.airbag factory component.

Stopping the org.equinoxosgi.toast.dev.airbag bundle using the console’s stop command demonstrates how the airbag component factory correctly disposes of airbag components when deactivated. Likewise, using the start command to restart it causes the airbag components to be manufactured again.

15.3 Launching and Debugging DS Applications

Launching an application that uses DS is like launching any other OSGi application—you just need a few extra bundles. In particular, ensure that the following three bundles are in your launch configuration:

org.eclipse.equinox.dsThe DS implementation

org.eclipse.equinox.utilUtilities used by the DS implementation

org.eclipse.osgi.servicesThe OSGi standard API

Bundles that use DS often do so entirely via XML and do not specify a static dependency upon the DS implementation bundle org.eclipse.equinox.ds. This makes it easy to forget to include this bundle in the launch configuration. It is also important to ensure that the org.eclipse.equinox.ds bundle is started, since only then will it detect bundles that use DS and process their XML.

While we do not recommend that you use start levels, using start levels with DS bundles requires special care. Equinox uses a default start level of 4, so if your DS bundles need a start level lower than 4, let’s say 3, you must remember to set the org.eclipse.equinox.ds bundle’s start level to 3 or lower to ensure that your bundle’s DS components are processed early enough. If you forget to do this, they will be processed at start level 4 after the org.eclipse.equinox.ds bundle is started. For this reason some people simply set the org.eclipse.equinox.ds bundle’s start level to 1 just to be safe.

Given the loose coupling and laziness provided by DS, there can be some additional debugging problems. In particular, problems with parsing XML and other service binding issues can lead to many late-night debugging frustrations. Fortunately, the Equinox DS implementation has a helpful debugging flag that echoes all error messages to the console. Set the following VM argument when you launch your application:

-Dequinox.ds.print=true

The DS specification says that errors encountered while parsing and processing the component XML documents must be written to the LogService, if available. To use this, install and start the Equinox log bundle, org.eclipse.equinox.log. This bundle registers a memory-based LogService and a LogReaderService that supports the reading of logged events. You can also use the Equinox console’s log command to dump recent log events to the console.

Equinox’s DS implementation registers a CommandProvider service that extends the available console commands. The following Service Component Runtime commands are available that are helpful for controlling, understanding, and debugging a DS application:

list [-c] [bundle id]List all components, or the components that belong to the bundle with the specified bundle ID. Use -c to display complete component information. Using –c and a bundle ID is useful for debugging a particular bundle. The short form is ls.

component <component id>Display the details of the component with the specified component ID. Use the list command without parameters to display all components and their component IDs. The short form is comp.

enable <component id>Enable the component with the specified component ID. The short form is en.

disable <component id>Disable the component with the specified component ID. The short form is dis.

enableAll [bundle id]Enable all components. Specify a bundle ID to enable only the components that belong to a particular bundle. The short form is enAll.

disableAll [bundle id]Disable all components. Specify a bundle ID to disable only the components that belong to a particular bundle. The short form is disAll.

15.4 PDE Tooling

Having been introduced to Declarative Services, seen some of the common usage scenarios, and started to learn about the component XML, you’ll be pleased to know that the Eclipse PDE provides some excellent DS tooling. The PDE tooling includes a DS component definition wizard for generating an initial component XML document and an editor for working with components.

The component wizard generates a component XML document after gathering details such as its location and file name, the name of the component it describes, and the component’s implementation class name.

In addition, the wizard updates the ServiceComponent header in the bundle’s manifest to reference the component XML document. This is particularly helpful since it’s easy to forget, and DS cannot find your component without it.

Figure 15-1 shows the Overview page of the component definition editor. The Component section of the page is used to configure general component settings such as its name, implementation class, and lifecycle methods. Clicking the Class*: link opens the New Java Class wizard, providing a shortcut for creating the component’s implementation class; once created, the link provides a way to quickly navigate to the class. The Browse... button provides a way to pick an existing class.

Figure 15-1 The Overview page of the component definition editor

image

The Options section is used for less common capabilities such as defining a factory component, setting the component’s configuration policy, and controlling its enablement and immediacy settings.

The Properties section is where single component properties and component property files are declared. For a single property the Edit... button allows the property name, type, and value to be edited, and for a properties file it allows the location and file name to be edited.

Figure 15-2 shows the Services page where referenced and provided services are defined. Each referenced service can be edited to set attributes such as its name, interface, cardinality and policy, bind and unbind method names, and its target.

Figure 15-2 The Services page of the component definition editor

image

Provided services are shown in the lower half of the Services page, and each can be edited to change its interface name.

Table 15-1 shows the various images that are used to decorate a component’s services.

Table 15-1 Icons Used to Represent Referenced and Provided Services

image

Of course, there is also the Source page that supports text editing of component XML, but you’ll likely find that this is unnecessary.

All this is not to say that the tooling is perfect; having made its debut only in Eclipse 3.5, it is still maturing and will likely be enhanced with future releases. It will likely improve its validation of the component XML and its error reporting. While the form-based editors make composing a component easy, errors reported in the Problems view are currently displayed only as markers on the Source page of the editor.

15.5 Summary

Successfully building a service-oriented OSGi application requires that the bundle developer understands the dynamic nature of the OSGi service model. Until the release of Declarative Services in OSGi R4, it was a significant challenge to build an appropriately behaved application, even of moderate complexity. But with the introduction of Declarative Services it is now possible to build a scalable, dynamic, loosely coupled application from OSGi bundles.

In this chapter we have introduced Declarative Services and some of the common scenarios where it can be applied. We taught you enough to be productive with DS, and we discussed the PDE tooling that supports building DS components.

For a deep dive on the component XML schema and the DS component lifecycle, see Chapter 24, “Declarative Services Reference.”

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

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