Chapter 24. Declarative Services Reference

Chapter 15, “Declarative Services,” introduced DS and the common usage scenarios; this chapter dives deeply into the component XML schema to provide you with a better understanding of how to use DS and how to work with its component lifecycle. In particular, we

• Detail the Declarative Services XML schema v1.1.0, which is used to describe DS components

• Discuss the DS component lifecycle and how components interact with the dynamic changes of the OSGi service model

24.1 Component XML Schema v1.1.0

The element structure of a DS component XML document is relatively simple. Every DS component has an implementation class and may optionally define properties and identify services it references and provides. The element structure is summarized in Table 24-1 and is detailed in the following sections.

Table 24-1 Overview of the Component XML Schema v1.1.0

image

24.1.1 Declaring the XML Namespace and Schema

In Release 4, version 4.1, of the OSGi specification, the DS XML schema was defined by http://www.osgi.org/xmlns/scr/v1.0.0. This is the schema used by Equinox 3.4. For Release 4, version 4.2, a new DS XML schema—http://www.osgi.org/xmlns/scr/v1.1.0—was introduced. All DS components in this book use this schema.

By default a DS component uses the v1.0.0 schema. Since there are now multiple schemas, we recommend that you always define an XML namespace to use the schema with which your component complies. An XML namespace is typically defined using the <component> element and the namespace scr. For example:

image

The scr namespace identifier must be specified only on the <component> element. Specifying scr on any nested elements will cause DS to report errors against the XML document.

Contributed XML documents can contain any number of <component> elements nested at any level. An XML namespace must be used if you are declaring multiple components in a single document or are nesting a <component> element in an XML document that uses a different namespace. To use the namespace, the root element must include a namespace declaration, and the recommended prefix for the namespace is scr, for example:

xmlsn:scr="http://www.osgi.org/xmlns/scr/v1.1.0"

To declare multiple components in a single XML document, make sure that the root element is not a <component> element and that all <component> elements use the declared namespace, which in this case is scr:

image

While it is possible to describe multiple components in a single XML document and to nest DS components inside documents with different XML schemas, the PDE tooling in Eclipse 3.5.x does not support this.

24.1.2 The <component> Element

Each <component> element describes a single DS component. This element is required. The <component> element has the following attributes:

nameA bundle-unique name of the component. This attribute is optional, defaulting to the value of the component’s <implementation> element’s class attribute. If multiple components share an implementation class, setting this attribute is required to avoid duplicates.

The value of this attribute is used by other components within the same bundle that wish to enable or disable it using the ComponentContext API; see the description of the enabled attribute for details.

Depending on the value of the <component> element’s configuration-policy attribute, the value of this attribute may also be used as a framework-unique persistent identifier by the ConfigurationAdmin service; see Section 24.2.1.2 for more on the configuration-policy attribute.

activateThe name of the implementation class method DS calls when the component’s configuration is satisfied and the component is activated. This attribute is optional, defaulting to activate. See Section 24.2.2 for more on component activation.

deactivateThe name of the implementation class method DS calls when the component’s configuration is no longer satisfied and the component is deactivated. This attribute is optional, defaulting to deactivate. See Section 24.2.2 for more on component deactivation.

modifiedThe name of the implementation class method DS calls when the ConfigurationAdmin service’s Configuration for the component has been modified. This attribute is optional, and there is no default value. Setting this attribute does not make sense if the configuration-policy attribute has been set to ignore. See Section 24.2.5.2 for more on configuration modification.

immediateControls whether the component’s implementation class should be instantiated and the component activated immediately upon its configuration being satisfied. This attribute is optional. The default value of the attribute depends on other characteristics of the component:

true—When the component does not provide any services and is not a factory component. In this case the immediate attribute is implicitly true and cannot be set to false.

false—When the component is a factory component. In this case the immediate attribute is implicitly false and cannot be set to true.

It makes sense to explicitly set this attribute to true only when the component provides a service and you do not want the component’s activation to be delayed until the first request for a provided service is received. It never makes sense to explicitly set this attribute to false. See Section 24.2.4, “Component Immediacy,” for more on component immediacy.

enabledControls whether the component is enabled upon creation. This attribute is optional, defaulting to true. It never makes sense to explicitly set this attribute to true.

A component can programmatically enable and disable other components within the same bundle using the ComponentContext’s enableComponent and disableComponent methods and passing the component’s name attribute as a parameter. See Section 24.2.1.1, “Component Enablement,” for more on component enablement and disablement.

configuration-policyControls whether the component depends on the availability of a ConfigurationAdmin service that has a Configuration with a persistent identifier equal to the component’s name attribute. This attribute is optional, defaulting to optional. Legal configuration-policy values are

require—Use this value if the component’s configuration can be satisfied only when there is a ConfigurationAdmin service that has a Configuration for the component.

optional—Use this value if the component’s configuration can be satisfied regardless of whether there is a ConfigurationAdmin service and regardless of whether it has a Configuration for the component.

ignore—Use this value if the component does not wish to interact with the ConfigurationAdmin service. A component that uses this value does not need its name attribute to be a framework-unique persistent identifier but rather just a bundle-unique name.

factoryThe component’s factory ID. This attribute is optional. When this attribute is set, an org.osgi.service.component.ComponentFactory service is registered. Ideally a component’s factory ID should uniquely identify the factory, but there is no requirement for this to be the case. A component factory cannot be an immediate component.

24.1.3 The <implementation> Element

The <implementation> element describes the Java class that implements the behavior for the component. This element is required.

classThe fully qualified name of the class that implements the behavior of the component. This attribute is required. This must be a public, concrete class, with a default constructor, and must be a subtype of all the types described by the component’s <provide> elements, if any. Section 24.1.7, “The <provide> Element,” discusses this further.

24.1.4 The <property> Element

The <property> element describes a single property of the component. Component properties are accessible to the component instance and will be registered with every service provided by the component. This element is optional. See Section 24.2.5, “Component Properties,” for more on component properties.

nameThe name of the property. This attribute is required.

valueThe value of the property. This attribute is required unless the element’s body describes the value of the property; this is discussed later.

typeThe type of the property. This attribute is optional, defaulting to String. This attribute dictates how the value is parsed. Legal values are

image

When using the value attribute, the property will always be an object type as specified by the type attribute. For example, specifying a value attribute of 10 and a type attribute of Integer will result in an Integer object. The following snippet declares two single-valued properties:

<property name="toast.devsim.host" value="localhost"/>
<property name="toast.devsim.port" value="8083" type="Integer"/>

While the value attribute is used to describe a single property value, the body of the <property> element is used to describe multiple property values, formatted one per line. In this case the property value is an array of the primitive types as specified by the type attribute. For example, if the type attribute is Long, the property value is a long[]. Multiple values of type String are represented as a String[]. The following declaration results in an int[] property value:

image

It is not possible to externalize and translate a <property> element’s value attribute or body content.

24.1.5 The <properties> Element

The <properties> element describes properties of the component, as defined in a properties file. As with the <property> element, these properties are accessible to the component instance and will be registered with each service provided by the component. This element is optional. See Section 24.2.5, “Component Properties,” for more on component properties.

entryA bundle-relative path to a properties file. This attribute is required. For portability reasons, favor forward slashes over backslashes as a path separator.

Rather than embedding the properties in the component XML document, this element identifies a file from which properties are loaded. All properties that are loaded using a <properties> element are of type String. When a bundle contains multiple components, it can be convenient to store common properties in a properties file that is loaded by each component.

24.1.6 The <service> Element

The <service> element describes the services to be registered with the OSGi service registry. This element is optional; however, if it exists, it must have at least one <provide> nested element, as described in Section 24.1.7, “The <provide> Element.”

servicefactoryThis attribute describes whether the component behaves as a service factory. This attribute is optional, defaulting to false. A service factory is special in that a unique instance of the component’s implementation class is created for each bundle that requests any of its provided services, rather than sharing a single instance with all requesting bundles.

24.1.7 The <provide> Element

The <provide> element identifies a single Java type under which a component’s implementation is registered with the OSGi service registry. This element is required but only as a child of the optional <service> element.

interfaceThe fully qualified name of a Java type. Despite its name, the attribute’s value may be either an interface name or a class name. The component’s implementation class must always be a subtype of the Java type named by this attribute. This rule is enforced by DS at runtime when it instantiates the component’s implementation class.

24.1.8 The <reference> Element

The <reference> element describes a single prerequisite service of the component. This element is optional. A referenced service is satisfied when DS has acquired it from the OSGi service registry. Likewise, a referenced service is unsatisfied when it can no longer be acquired from the OSGi service registry.

nameA component-unique name for the referenced service. This attribute is optional, defaulting to the value of the interface attribute. The value of the attribute is used by the component’s implementation class to programmatically locate the referenced service via the ComponentContext's API. In the rare case where a component has multiple <reference> elements with the same interface attribute, it is necessary to explicitly set the name attribute.

interfaceThe fully qualified Java type of the referenced service. This attribute is required. The rules for this attribute follow those of the <provide> element’s interface attribute. Again, while it is legal to specify a Java class, you should strive to specify a Java interface.

bindThe name of a method in the component’s implementation class that is used to bind the referenced service. This attribute is optional. See Section 24.2.3, “Accessing Referenced Services,” for more on binding referenced services.

unbindThe name of a method in the component’s implementation class that is used to unbind the referenced service. This attribute is optional. See Section 24.2.3, “Accessing Referenced Services,” for more on unbinding referenced services.

cardinalityThe number of referenced service instances that the component must acquire before its configuration is satisfied. This attribute is optional, defaulting to 1..1. There are only four legal values for this attribute:

0..1—Optional and unary

0..n—Optional and multiple

1..1—Required and unary

1..n—Required and multiple

See Section 24.2.1.3, “Acquisition of Referenced Services,” for more on referenced service cardinality values.

policyThis attribute describes how changes in the referenced service are handled by the component. This attribute is optional, defaulting to static. Legal values are

static—When using this policy, the component’s implementation sees changes in referenced services only while deactivated. This means that if the component is activated, DS will deactivate the component before it sees the change. If the component’s configuration continues to be satisfied, DS will activate the component once more.

dynamic—When using this policy, the component’s implementation dynamically sees changes in the referenced service. If the component is activated, DS will not deactivate the component before it sees the change. This policy requires the component’s implementation to be tolerant of dynamic changes to referenced services.

Using the static policy ensures that a component’s activate and deactivate methods are not called asynchronously while a referenced service is being bound and unbound. This is not true when using the dynamic policy.

targetThis attribute is an LDAP filter allowing for finer-grained selection of a referenced service. This attribute is optional. If your LDAP filter includes illegal XML characters, such as <, >, or &, you must encode them. For example, use &lt; instead of <, &gt; instead of >, and &amp; instead of &.

24.2 The Component Lifecycle

A component has a lifecycle that controls when it is activated and deactivated. A bundle must be started before DS can process its components. When a bundle is in the ACTIVE state, or is in the STARTING state and has its Bundle-Activation manifest header set to lazy, DS will parse its Service-Component manifest header’s list of XML documents and creates the components described by each <component> element.

For each component, DS ensures that its configuration is satisfied before activating it. DS deactivates an activated component when its configuration becomes unsatisfied, or when its hosting bundle is stopped. Unless the hosting bundle is stopped, a component is deactivated and reactivated as its configuration goes from being satisfied to being unsatisfied, to being satisfied once more. The details of how configurations are satisfied are discussed in the next section.

24.2.1 Satisfying a Component’s Configuration

A component’s configuration is considered satisfied when

• The component is enabled

• If the <component> element’s configuration-policy attribute is set to require, there is a registered ConfigurationAdmin service that has a Configuration with a persistent identifier equal to the <component> element’s name attribute

• All of the component’s referenced services have been acquired per their cardinality attribute

You’ll recall from Section 24.1.8, “The <reference> Element,” that the <-reference> element’s cardinality attribute describes whether the service is required or optional and how many instances of the service are required and desired by the component.

24.2.1.1 Component Enablement

The first configuration constraint to be checked is whether the component is enabled. By default a component is enabled as soon as it is created. An enabled component’s configuration is managed by DS, whereas a disabled component’s is not and is effectively dormant. Most components are enabled by default and are never disabled.

Component enablement and disablement are useful when initialization behavior must be performed before a component is enabled, or when the component is enabled only while a condition remains true. For example, perhaps a roadside assistance component is enabled only after the billing component has queried a remote billing server to check that the driver has paid for roadside assistance.

The automatic enablement of a component can be suppressed by setting the <component> element’s enabled attribute to false. Once disabled, a component can be enabled only via another ComponentContext in the same bundle by calling that ComponentContext’s enableComponent method and passing as a parameter the name of the component to enable. Passing null to the enableComponent method enables all components in the bundle.

A component can disable another component by calling the ComponentContext’s disableComponent method and passing as a parameter the name of the component to disable. Unlike the enableComponent method, it is not legal to pass null to the disableComponent method, and doing so will result in an exception being thrown.

The enableComponent and disableComponent methods execute asynchronously, meaning that they may return before the component’s enablement or disablement is complete.

24.2.1.2 Availability of a ConfigurationAdmin Service Configuration

If the <component> element’s configuration-policy attribute is set to require, the component’s configuration is satisfied only while there is a registered ConfigurationAdmin service that has a Configuration with a persistent identifier that equals the <component> element’s name attribute.

If the <component> element’s configuration-policy attribute is set to optional or ignore, the satisfaction of the component’s configuration is unaffected by the availability of the ConfigurationAdmin service or whether it has Configuration for the component.

24.2.1.3 Acquisition of Referenced Services

The third configuration constraint to be satisfied is the cardinality of each of the component’s referenced services. A referenced service’s cardinality is described using the <reference> element’s cardinality attribute.

A referenced service’s cardinality consists of two values: a lower bound and an upper bound. As discussed in Section 24.1.8, “The <reference> Element,” there are four cardinality values: two that describe a required service, and two that describe an optional service. The two cardinality values that describe a required service have a lower bound of 1:

1..1—The component uses exactly one service.

1..n—The component uses one or more services.

The two cardinality values that describe an optional service have a lower bound of 0:

0..1—The component uses at most one service.

0..n—The component uses zero, one, or many services.

Choosing the cardinality is a simple matter of answering two questions:

Is the service required or optional?

Required—Set the lower bound to 1.

Optional—Set the lower bound to 0.

Does the component use one or many instances of the service?

One—Set the upper bound to 1.

Many—Set the upper bound to n.

While the cardinality that you choose applies only to a particular referenced service, it takes only a single unavailable required referenced service to cause the component’s configuration to remain unsatisfied and the component to not be activated.

24.2.2 Component Activation, Deactivation, and Modification

The <component> element’s activate, deactivate, and modified attributes name the methods of the component implementation class that DS calls when the component is activated, deactivated, and modified.

Activation and modification methods can take zero or more arguments, where each argument is of one of the following types:

ComponentContextA ComponentContext is similar to the bundle’s BundleContext in that it provides an OSGi-defined API for querying and controlling the component and other components defined by the bundle.

BundleContextThe hosting bundle’s BundleContext.

MapAn immutable Map containing the component’s properties.

DS searches for activation and modification methods in the component’s implementation class in the following order:

1. A one-argument method that takes a ComponentContext

2. A one-argument method that takes a BundleContext

3. A one-argument method that takes a Map

4. A two-argument method that takes a ComponentContext, BundleContext, or Map, in any order; if DS finds multiple matching methods, it will arbitrarily choose one

5. A zero-argument method

If upon calling the activate method an exception is thrown, DS will log an error to the LogService, if available, and the component is not activated.

Once a component is activated, it remains so until its configuration becomes unsatisfied or its defining bundle is stopped, at which time the component is deactivated.

Deactivation methods can take zero or more arguments, where each argument is of one of the following types:

ComponentContextSimilar to the bundle’s BundleContext in that it provides an OSGi-defined API for querying and controlling the component and other components defined by the bundle

BundleContextThe hosting bundle’s BundleContext

MapAn immutable Map containing the component’s properties

int or IntegerThe reason the component is being deactivated

DS searches for deactivation methods in the component’s implementation class in the following order:

1. A one-argument method that takes a ComponentContext

2. A one-argument method that takes a BundleContext

3. A one-argument method that takes a Map

4. A one-argument method that takes an int

5. A one-argument method that takes an Integer

6. A two-argument method that takes a ComponentContext, BundleContext, Map, int, or Integer in any order; if DS finds multiple matching methods, it will arbitrarily choose one

7. A zero-argument method

When DS calls a deactivation method that takes an int or an Integer, one of the following deactivation reasons is passed as a parameter:

0—Unspecified

1—The component was disabled

2—A reference became unsatisfied

3—A configuration was changed

4—A configuration was deleted

5—The component was disposed

6—The bundle was stopped

Throughout its lifetime a component may be activated and deactivated many times as its configuration becomes satisfied and unsatisfied. Each time a component is activated, a new instance of the component’s implementation class and the ComponentContext is instantiated, and the component’s referenced services are bound.

The component’s activate, deactivate, and modified methods will not be called asynchronously by DS. When the component has a <reference> element that uses the dynamic policy, DS will call its bind and unbind methods asynchronously to these methods.

24.2.2.1 Referenced Service Policy

The <reference> element’s policy attribute describes how the component will handle changes in the referenced service. There are two values for the policy attribute:

staticThis policy ensures that once activated, the component does not see referenced service changes without being deactivated first. Once the component has been deactivated, it will be activated only when its configuration is satisfied once more. This is the default policy.

dynamicThis policy allows the referenced service to change dynamically without deactivating the component first.

The decision regarding the policy to choose is often influenced by the cardinality of the referenced service. Generally speaking, the most common cardinality and policy pairings are

1..1 and staticThis is the default, simplest, and most common pairing. The component requires exactly one instance of the referenced service, is activated only when the service is available, and is deactivated when the service becomes unavailable.

0..1 and staticSpecifying a cardinality with a lower bound of 0 makes the referenced service optional. This is common in scenarios such as logging or where graceful fallback is possible. Note that the component author must carefully handle the case where a service is, or is not, present. The presence or absence of optional referenced services does not affect the activation of the component.

0..1 and dynamicThis variation on the optional service requirement can be useful in highly fluid scenarios. The main difference is that the service can appear and disappear at any time. Pragmatically the coding patterns required here are complicated, so care should be taken.

0..n and dynamicThese settings are common in listener or Whiteboard Pattern cases, as discussed in Chapter 15, “Declarative Services.” The component will bind with any number of services and be told of their transitions without affecting the activation state of the component. See the Portal component in Chapter 13, “Web Portal,” for an example.

When using the dynamic policy, it is common to use bind and unbind methods to manage changes in the referenced services. For the multiple cardinalities (1..n and 0..n) this typically means that the referenced service is added to a collection when bound and removed from the collection when unbound. For the 0..1 cardinality, the referenced service is typically cached in a field when bound and the field is set to null when unbound.

If you use the dynamic policy with one of the unary cardinalities (0..1 and 1..1), when a bound referenced service is unregistered, DS will always try to rebind a replacement service before it unbinds the current service. This can come as a big surprise since while the cardinality dictates that only a single referenced service is required, the component must be able to handle it being dynamically switched for another referenced service due to the cardinality constraints. For an example of this, see Section 17.2, “Using the LogService in Toast.”

If you use the static policy with one of the optional cardinalities (0..1 and 0..n), the component’s configuration can be satisfied with zero referenced services. The static policy dictates that once the component’s configuration is satisfied, it will not be deactivated and reactivated if a referenced service becomes available later. For this reason we suggest using the dynamic policy with the optional cardinalities.

24.2.3 Accessing Referenced Services

There are two strategies that a component can use to access its referenced services:

Event Strategy—Using this strategy, DS dispatches events to the component as the availability of its referenced services changes. Set the <reference> element’s bind and unbind attributes to the name of the implementation class methods that DS calls to handle these events.

Lookup Strategy—Using this strategy, the <reference> element’s bind and unbind attributes are typically not set. Instead, the component’s implementation looks up each referenced service using its ComponentContext’s API.

It is not necessary for a component to use the same strategy for accessing all of its referenced services, since the strategy you pick is influenced by the referenced service’s cardinality and policy.

We recommend that you start by using the Event Strategy since it is simple, fits well with POJO APIs, and works well regardless of the referenced service’s cardinality and policy. The Toast application uses the Event Strategy in all but a few cases. For an example of the Lookup Strategy, see the org.equinoxosgi.toast.backend.portal bundle where the PortalServlet dynamically looks up IPortalAction referenced services based on an HTTP request.

24.2.3.1 Using the Event Strategy

The Event Strategy allows referenced services to be mapped to the API of the component’s implementation class via the <reference> element’s bind and unbind attributes. The signature of the bind and unbind method can be one of the following:

void <method>(<service-type>)This method takes a simple argument that is typed to the <reference> element’s interface attribute or one of its super-types. At runtime the parameter is the actual service object. This is the most commonly used signature.

void <method>(<service-type>, Map properties)This method’s first argument is as described in the previous signature. The second argument is a Map that contains the referenced service’s registered properties.

void <method>(ServiceReference reference)This method delays the loading and instantiation of the referenced service’s class by taking a ServiceReference argument.

DS searches for methods in the component’s implementation class in the following order:

1. Search for a single-argument method that takes a ServiceReference.

2. Search for a single-argument method that is typed to the <reference> element’s interface attribute.

3. Search for a single-argument method that is typed to a super-type of the <-reference> element’s interface attribute. If DS finds multiple matching methods, it will arbitrarily choose one.

4. Search for a two-argument method, with the first argument typed as the <reference> element’s interface attribute and the second argument typed as a Map.

5. Search for a two-argument method, with the first argument typed as a super-type of the <reference> element’s interface attribute and the second argument typed as a Map. If DS finds multiple matching methods, it will arbitrarily choose one.

DS requires that the visibility of these methods be such that they are accessible to the component’s implementation class. We recommend that you always make these methods public. We say this because they are necessary to use the class outside of OSGi and are really part of the component implementation class’s public API in a POJO context. Since these methods are never part of any provided service API, they will never be accessible to consumers of the provided service regardless of their visibility modifier.

Remember, it is desirable for your component implementation classes to remain pure POJOs, independent of OSGi APIs and mechanisms such as DS. For this reason, we recommend that you think carefully before defining bind and unbind methods that take a ServiceReference argument; doing so creates a dependency upon OSGi.

When the bind method takes a service instance argument, the referenced service’s implementation class clearly must have been loaded and instantiated before being passed as a parameter to the bind method. By contrast, when the bind method takes a ServiceReference argument, the referenced service’s implementation class is neither loaded nor instantiated before the bind method is called. This laziness is particularly valuable when using the multiple cardinalities, 0..n and 1..n, since a component often does not use every referenced service as soon as it is bound, but rather caches each ServiceReference and selects one based on criteria such as the referenced service’s registered properties. The reference service’s class is loaded and instantiated when the ServiceReference is dereferenced using the ComponentContext’s API locateService(String, ServiceReference).

24.2.3.2 Using the Lookup Strategy

While the Event Strategy involves DS injecting services by binding and unbinding the component’s referenced services, the Lookup Strategy involves the component’s implementation querying DS for its referenced services.

Of the two strategies, the Lookup Strategy is generally considered the lazier since a referenced service is reified into a service object only when a request for it is made. When using this strategy, referenced services are looked up via the component’s ComponentContext that provides the following API:

locateService(String name)This method locates a referenced service using the <reference> element’s name attribute.

locateService(String name, ServiceReference reference)This method locates a referenced service using the <reference> element’s name attribute and a ServiceReference. The name argument is necessary because a single ServiceReference can represent multiple service types, so specifying the name ensures that you locate a service object of the appropriate type. A component can obtain a ServiceReference in a variety of ways, but the most common way is by using the Event Strategy and having the ServiceReference dependency injected. When using this method, therefore, the Event Strategy and the Lookup Strategy are used together.

locateServices(String name)This method locates all the referenced services using the <reference> element’s name attribute. While this method can be used regardless of the referenced service’s cardinality, it is most commonly used with a multiple cardinality, namely, 0..n and 1..n.

The two locateService methods return an Object and the locateServices method returns an Object[], so it is necessary to cast the services to their actual types before use. Care must be taken to ensure that the name parameter passed to the methods is correct; otherwise an exception will be thrown when casting to the actual service type.

Since the ComponentContext is available only while the component is activated, locating services is typically done from the component’s activate method. This method should be typed to take a ComponentContext argument. Unfortunately ComponentContext is an OSGi class, and this makes it too easy to pollute a perfectly good POJO with an OSGi dependency. We recommend the following alternatives:

• Implement the component’s implementation class as an OSGi-dependent wrapper that delegates to a cached instance of the POJO. For this to work, the wrapper class must implement all the provided service interfaces and delegate to the cached POJO.

• Resign yourself to the fact that your component’s implementation class is OSGi-dependent and will never run as a POJO.

24.2.4 Component Immediacy

The concept of component immediacy is important to understand since it controls when a component is activated. Activation causes a component’s implementation class to be loaded and instantiated. One of the benefits that DS brings to the OSGi service model is lazy class loading and instantiation of the component’s implementation class. This can result in significant performance gains in terms of startup time and memory consumption.

An immediate component is activated as soon as its configuration is satisfied. By contrast, a delayed component has its activation delayed until one of its provided services is requested.

The <component> element’s immediate attribute is used to request the component’s activation characteristics, but it is important to remember that this attribute is merely a hint to DS rather than a demand. A component is immediate when

• It does not provide any services. DS considers the component to be implicitly immediate.

• Its immediate attribute is explicitly set to true.

There is no guarantee that DS will honor a component’s immediacy hint. Regardless of the value of its immediate attribute,

• If the component is a factory component, it will not be immediate. A factory component must always have its component activation delayed since its purpose is to provide a service through which component instances are dynamically created and activated.

• If the component does not provide any services, and is not a factory component, it will always be immediate. Without any provided services, a component is at the top of the food chain and must therefore be activated immediately.

Since many components provide services, immediate components are rare. Examples of immediate components include

• A user interface component that needs to display a shell when the application starts.

• A component that registers servlets rather than services. A servlet must always be registered before an HTTP request for it is received.

• A component that performs asynchronous data collection from a device such as a thermometer, which may or may not provide services.

Remember that the activation of a component may be the cause of a potentially large chain of component activations, class loading, and instantiation of objects across the entire system. For performance reasons, care must be taken before making a component immediate. Since a well-designed OSGi application is composed of many finely grained components, it is important to understand the true cost of activating a single component.

24.2.5 Component Properties

A component’s properties can be set in three ways, in order of precedence:

• A component factory accepts properties passed via the ComponentFactory’s newInstance API that is used to create new component instances.

• If a <component> element’s configuration-policy attribute is set to either require or optional, the ConfigurationAdmin service can be used to create and update a Configuration for the component. See Section 24.1.2, “The <component> Element.”

• Finally, a component’s properties can be set statically in the component’s XML document using <property> and <properties> elements. See Sections 24.1.4, “The <property> Element,” and 24.1.5, “The <properties> Element.”

This means that when a property is passed to a component by a component factory, it is not possible to configure the property via the ConfigurationAdmin service, since the properties passed by the component factory will always override those of the configuration managed by ConfigurationAdmin. Likewise, when a component is using ConfigurationAdmin to manage its properties, updating its Configuration will override the properties defined in the component’s XML document.

Regardless of how a component’s properties are set, they are presented to the component as a single immutable Dictionary via its ComponentContext’s getProperties method. See Chapter 13, “Web Portal,” for an example of using properties.

A component’s properties are also registered as properties of any service that it provides. The exception to this rule is that properties whose name starts with a dot (“.”) are considered private to the component and will not be registered with provided services.

24.2.5.1 Component Properties and the ConfigurationAdmin Service

The DS specification has always included close integration with the ConfigurationAdmin service as a way of remotely and persistently configuring a component’s properties.

In v1.0.0 of the DS schema, DS always attempts to acquire the ConfigurationAdmin service to look for a Configuration with a persistent identifier equal to the <component> element’s name attribute. If a Configuration is found, its properties are used to override those defined in the component’s XML declarations. In this context properties are defined as

• A property described by the <property> element.

• A property described by a <properties> element.

• Each referenced service’s target property as described by its <reference> element’s optional target attribute. Target properties are discussed in Section 24.2.5.3, “Referenced Service Target Properties.”

This is certainly a useful capability since otherwise there is no other way to configure a component’s properties, which are often statically declared in XML and for which there is no programmatic API that allows them to be changed.

In v1.1.0 of the DS schema the <component> element attribute configuration-policy was introduced, which allows a component to more accurately describe its integration with the ConfigurationAdmin service. A component can now

• Require a ConfigurationAdmin service and a Configuration before its configuration is considered satisfied. If the component is a factory component and there is no ConfigurationAdmin service and a Configuration, the ComponentFactory service will not be registered.

• Optionally use the ConfigurationAdmin service with a matching Configuration.

• Ignore the ConfigurationAdmin service. In v1.0.0 of the DS schema every component interacted with the ConfigurationAdmin service, if available. Now there is a way of opting out.

The <component> element’s configuration-policy attribute is discussed in Section 24.1.2, “The <component> Element.”

24.2.5.2 Component Configuration Modification

In v1.0.0 of the DS schema, updates to a component’s Configuration resulted in the component always being deactivated and reactivated regardless of the changes to the properties. In v1.1.0 of the DS schema, the <component> element’s modified attribute was added. This attribute can be set to the name of a method in the component’s implementation class that DS calls when the component’s Configuration has been updated such that its configuration remains satisfied. The signature of the method named in this attribute is discussed in Section 24.2.2, “Component Activation, Deactivation, and Modification.”

24.2.5.3 Referenced Service Target Properties

As discussed in Section 24.1.8, “The <reference> Element,” a <reference> element has an optional target attribute that is used to finely tune the referenced services that the component acquires. The target attribute’s value is an LDAP filter that is used by DS to satisfy the constraints of the referenced service based on its registered properties, for example:

image

In this example the referenced service’s target property is the LDAP filter (http.port=80). The component’s configuration will be satisfied only if an HttpService is acquired that has an http.port property with the value 80. Recall that the <property> and <properties> elements are used by a component to describe the properties that will be registered with its provided services.

While a referenced service’s target property is described statically in XML, it can be configured dynamically, just like any other component property, but by using its target property key. A target property key is the concatenation of the <reference> element’s name attribute and the suffix .target, which would be http.target in our example.

24.3 Summary

The Declarative Services XML schema is certainly not complicated, but to use DS effectively it is helpful to understand its subtleties. In this chapter we dived deeply into the schema to describe every element and attribute, as well as how the various attribute values affect components’ behavior.

We have also discussed the DS component lifecycle with the goal of teaching you to build flexible and pluggable applications composed from OSGi services. Toast is built entirely of DS components and services and uses DS to good effect. With the knowledge you have gained from Chapter 15, “Declarative Services,” and the discussion in this chapter, we hope that you’ll quickly be able to leverage the benefits of building applications composed of loosely coupled and highly cohesive components and services.

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

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