## Chapter 11. Compendium Services

The OSGi Service Platform Service Compendium specification defines a number of additional services that may be supported by OSGi implementations. Gemini Blueprint supports an additional "compendium" namespace that provides integration with some of these services. By convention, the prefix `osgix` is used for this namespace:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/osgi"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/osgi
           	http://www.springframework.org/schema/osgi/spring-osgi.xsd
         http://www.springframework.org/schema/osgi-compendium
           	http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd
         http://www.springframework.org/schema/beans
           	http://www.springframework.org/schema/beans/spring-beans.xsd">

       <!-- use the OSGi namespace elements directly -->
       <service id="simpleServiceOsgi" ref="simpleService"
           interface="org.xyz.MyService" />

       <!-- qualify compendium namespace elements -->
       <osgix:cm-properties id="cm" persistent-id="com.xyz.myapp"/>

    </beans:beans>

| Compendium namespace declaration (bound to `osgix` prefix)
| Schema location (namespace URI)
| XML schema to use for the compendium namespace

At present this namespace provides support for the Configuration Admin service. Support for other compendium services may be added in future releases.

## 11.1. Configuration Admin

One of the most important compendium services, is the Configuration Admin which, as a name implies, provides configuration to interested bundles through the OSGi service registry. Gemini Blueprint provides dedicated support for Configuration Admin (CM), allowing consumption and injection of the configuration data in a declarative way.

### 11.1.1. Exposing Configuration Admin Entries As `Properties`

In its simplest form, the CM can be seen as a configuration source, namely a `Dictionary` whose keys are always `String`s. Gemini Blueprint can expose entries in the CM as a `Properties` object, through the `cm-properties` element. A minimal declaration looks as follows:

    <osgix:cm-properties id="ds.cfg" persistent-id="data.source.office.1"/>

The configuration above, exposes the properties available in the CM under data.source.office.1 entry as a bean named ds.cfg.

| Note
The `persistent-id` attribute must refer to the persistent-id of an OSGi `ManagedService`, it is a configuration error to specify a factory persistent id referring to a `ManagedServiceFactory`.

Those familiar with Spring's util namespace will find `<osgi:cm-properties/>` element similar to `<util:properties/>`.

It is possible to specify a default set of property values to be used in the event that the configuration dictionary does not contain an entry for a given key. The declaration is similar to the `props` element inside the Spring beans namespace:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/osgi-compendium"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
       xsi:schemaLocation="
          http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/osgi-compendium
            http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

       <osgix:cm-properties id="cfg.with.defaults" persistent-id="data.source.office.2">
          <beans:prop key="host">localhost</beans:prop>
          <beans:prop key="port">3306</beans:prop>
       </osgix:cm-properties>

    </beans:beans>

By default, the properties found in the Configuration Admin entry will override the local properties. Thus, for the previous example, if the `data.source.office.2` configuration contains a host entry, its value will override the locally defined `localhost`. For cases where this behaviour is undesired, the attribute `local-override` (default `false`) allows one to revert the merging algorithm, forcing the local properties to override the entries in the CM.

Since `cm-properties` exposes the CM entries as `Properties`, it can be used with Spring's `PropertyPlaceholderConfigurer` and `PropertyOverrideConfigurer` to externalize and customize environment-specific properties:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
       xmlns:ctx="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
    	http://www.springframework.org/schema/beans
    	  http://www.springframework.org/schema/beans/spring-beans.xsd
    	http://www.springframework.org/schema/context
    	  http://www.springframework.org/schema/context/spring-context.xsd
    	http://www.springframework.org/schema/osgi-compendium
    	  http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">

       <!-- Configuration Admin entry -->
       <osgix:cm-properties id="cmProps" persistent-id="com.xyz.myapp">
          <prop key="host">localhost</prop>
       </osgix:cm-properties>

       <!-- placeholder configurer -->
       <ctx:property-placeholder properties-ref="cmProps" />

       <bean id="dataSource" ...>
          <property name="host" value="${host}"/>
          <property name="timeout" value="${timeout}"/>
       </bean>

    </beans>

An important aspect of `cm-properties` is does not reflect any that any subsequent changes made to the entry it represents, made through the Configuration Admin API. That is, once resolved, the `cm-properties` content remains the same, regardless of any updates made the to CM entry it represents.

### 11.1.2. Managed Properties

Based on a configuration admin entry, Gemini Blueprint can autowire by name, the properties of a given bean. To use this feature, define a nested `managed-properties` inside the bean definition:

    <bean id="managedComponent" class="MessageTank">
       <osgix:managed-properties persistent-id="com.xyz.messageservice"/>
    </bean>

For each key in the dictionary stored by Configuration Admin under the given persistent id, if the bean type has a property with a matching name (following JavaBeans conventions), then that component property will be dependency injected with the value stored in Configuration Admin under the key. If the definition of `SomeClass` from the example above is as follows:

    public class MessageTank {
      private int amount;
      public int getAmount() { return this.amount; }
      public void setAmount(int amount) { this.amount = amount; }
    }

and the configuration dictionary stored under the pid `com.xyz.messageservice` contains an entry `amount=200`, then the `setAmount` method will be invoked on the bean instance during configuration, passing in the value `200`.

If a property value is defined both in the configuration dictionary stored in the Configuration Admin service and in a property element declaration nested in the component element, then the value from Configuration Admin takes precedence:

    <bean id="managedComponent" class="MessageTank">
       <osgix:managed-properties persistent-id="com.xyz.messageservice"/>
       <property name="amount" value="100"/>
       <property name="threshold" value="500"/>
    </bean>

Property values specified via property elements can therefore be treated as default values to be used if none is available through Configuration Admin.

| Warning
Do not share the same persistent-id (PID) between multiple bundles or definitions, as only one of them will receive notifications. `managed-properties` relies on `org.osgi.service.cm.ManagedService` contract which mandates that each `ManagedService` instance must be identified with its own unique PID. Please see the Configuration Admin spec, specifically section 104.3 and 104.5

#### 11.1.2.1. Configuration Admin Runtime Updates

A powerful feature of Configuration Admin is the ability to update (or delete) entries at runtime. That is, the configuration data stored in Configuration Admin may be updated after the bean has been created. By default, any post-creation updates will be ignored. However, one can configure `managed-properties` element to receive configuration updates through the `update-strategy` attribute, which can have a value of either `bean-managed` or `container-managed`.

`bean-managed` strategy will pass all the updates made to the configuration to a callback present on the bean, specified through the `update-method` attribute (which becomes required). The update method must have one of the following signatures:

    public void anyMethodName(Map properties)
    public void anyMethodName(Map<String,?> properties); // for Java 5

In contrast, the `container-managed` update strategy will re-inject bean properties by name based on the new properties received in the update. For `container-managed` updates, the component class must provide setter methods for the component properties that it wishes to have updated. Consider the following class definitions:

    public class ContainerManagedBean {
      // will be reinjected (since it has a setter)
      private Integer integer;
      // will not be reinjected (no setter present)
      private Long waitTime;

      public void setInteger(Integer integer) { this.integer = integer; }
    }

    public class SelfManagedBean {

      // update callback
      public void updateCallback(Map properties) {
    	System.out.println("Received properties " + properties);
    	System.out.println("Props can be used as a Dictionary " + (Dictionary) properties);
    	// do more work ...
      }
    }

and configuraton:

    <bean id="containerManaged" class="ContainerManagedBean">
       <osgix:managed-properties persistent-id="labX" update-strategy="container-managed"/>
       <property name="integer" value="23"/>
    </bean>

    <bean id="beanManaged" class="SelfManagedBean">
       <osgix:managed-properties persistent-id="labY" update-strategy="bean-managed" update-method="updateCallback"/>
    </bean>

Any updates made to the CM entry `labX` will be automatically reinjected on existing instances of `containerManaged` bean while the `labY` updates will be passed to `updateCallback` method.

The update options are summarized in the table below:

Table 11.1. Managed Properties Update Options

`update-strategy` | `update-method` | Behaviour
--- | --- | ---
`container-managed` | ignored | Reinjects the bean properties, using the properties present in the update. The re-injection will be applied while locking (through a `synchronized` instruction) the bean instance. If the locking or re-injection strategy is not suitable, consider using the `bean-managed` approach.
`bean-managed` | required | Invokes the `update-method` callback on the bean instance, passing the updated configuration (as a `Map` object that can be safely cast to a `Dictionary` if needed). No locking is performed.

### 11.1.3. Managed Service Factories

The Configuration Admin service supports a notion of a managed service factory(see section 104.6 in the Compendium Specification). A managed service factory is identified by a factory pid which allows multiple `Configuration` objects to be associated with the factory. `Configuration` objects associated with the factory can be added or removed at any point. The main intent of a factory is to create an OSGi service for each configuration: adding a new `Configuration` entry results in a new OSGi service being registered, removing a `Configuration`, unregisters the service. Gemini Blueprint provides support for the managed service factory concept through the `managed-service-factory` element. Once defined, the configuration associated with the factory pid will automatically create (or remove) bean instances which will be registered (or unregistered) in the OSGi space based on a template bean definition and the CM configuration.

This might sound more complicated then it actually is, so let's look at a simplistic example:

    <osgix:managed-service-factory id="simple-msf"
       factory-pid="com.xyz.messageservice"
       auto-export="all-classes">

       <bean class="com.xyz.MessageTank"/>
    </osgix:managed-service-factory>

| factory persistent id (pid)
| Shortcut flag used to determine under what interfaces the OSGi service is published (more info below)
| bean definition template. For each detected configuration, a new service will be created using the bean definition template.

In its simplest form, the `managed-service-factory` requires the factory pid, a bean definition used as a template and some information on how possible bean instances are published as services. Basically, the definition above instructs Gemini Blueprint to monitor the given factory pid (through a dedicated `ManagedServiceFactory` implementation (see the Compendium Spec for more info)) and for every `Configuration` object associated with the factory pid, to create a new, anonymous instance of the nested bean declared and export that instance as an OSGi service. The lifecycle of these beans instances is tied to the lifecycle of the associated `Configuration` objects. If a new configuration is added, a new bean is created and exported. If a configuration object is deleted or disassociated from the factory pid then the corresponding bean instance is destroyed.

In many regards, `managed-service-factory` acts as a specialized service exporter, similar to the `service` element but supporting the concept of managed properties. In fact, many of `service`'s attributes that indicate how a bean is exported, are found in `managed-service-factory` (as you saw in the previous example with `auto-export`) as are the `managed-properties` attributes.

The list of attributes can be found below:

Table 11.2. Managed Service Factory Options

Name | Values | Description
--- | --- | ---
interface | fully qualified class name (such as `java.lang.Thread`) | the fully qualified name of the class under which the object will be exported
context-class-loader | unmanaged | service-provider | Defines how the context class loader will be managed when an operation is invoked on the exported service. The default value is `unmanaged` which means that no management of the context class loader is attempted. A value of `service-provider` guarantees that the context class loader will have visibility of all the resources on the class path of bundle exporting the service.
auto-export | disabled `(default)` | interfaces | class-hierarchy | all-classes | Enables Spring to automatically manage the set of service interfaces advertised for the service. By default this facility is `disabled`. A value of `interfaces` advertises all of the Java interfaces supported by the exported service. A value of `class-hierarchy` advertises all the Java classes in the hierarchy of the exported service. A value of `all-classes` advertises all Java interfaces and classes.
update-strategy | none `(default)` | bean-managed | container-managed | Defines the update strategy for configuration modifications made after the associated beans have been created.

Similar to the `service` element, a list of interfaces or/and registration listeners can be declared to be notified when a service is being registered/unregistered. For more information on the semantics, please see Section 9.1.3, “Controlling The Set Of Advertised Service Interfaces For An Exported Service” and Section 9.1.10, “Service Registration And Unregistration Lifecycle” chapters.

Now that the `managed-service-factory` options have been explained, let's look at a more complex configuration:

    <bean id="queueTracker" class="org.xyz.queue.QueueTracker"/>

    <osgix:managed-service-factory id="data-msf"
       factory-pid="org.xyz.labX"
       update-strategy="bean-managed"
       update-method="refresh">
       <osgix:interfaces>
           <value>java.util.Collection</value>
           <value>java.util.Queue</value>
       </osgix:interfaces>
       <osgix:registration-listener ref="queueTracker"
           registration-method="track"
           unregistration-method="untrack"/>

       <bean class="com.xyz.ResizableQueue">
           <property name="size" value="100"/>
           <property name="concurrency" value="10"/>
           <property name="fair" value="false"/>
       </bean>
    </osgix:managed-service-factory>

| `ManagedServiceFactory` factory persistent id
| how should Gemini Blueprint behave when a `Configuration` is updated
| the method to invoke when for `bean-managed` updates
| the interfaces under which the nested beans are published as OSGi services
| listener notified when a service (based on the CM `Configuration`) is registered/unregistered
| custom (optional) service registration method
| custom (optional) service unregistration method
| bean definition template

The example above, creates a imaginary `ResizeableQueue` instance for each `Configuration` entry present under the `org.xyz.labX` factory pid. Each instance has default values assigned to `size`, `concurrency` and `fair` parameters. However, just like `managed-properties`, during the bean creation, the values received from the Configuration Admin will be injected by name, possibly overriding existing settings. Once created and configured, each nested, anonymous bean instance is registered as an OSGi service under the `java.util.Collection` and `java.util.Queue` interfaces. The OSGi service lifecycle is monitored by a registration listener, namely the bean `queueTracker`. Finally, due to the specified `update-strategy`, any updates executed to each CM configuration will cause the `refresh` callback to be invoked on the associated bean instance.

### 11.1.4. Direct Access To Configuration Data

The simplest way to work directly with the configuration data stored under a given persistent id or factory persistent id, is to register a service that implements either the `ManagedService` or `ManagedServiceFactory` interface and specify the pid that you are interested in as a service property (for more information, see the Configuration Admin chapter in the OSGi compendium spec). For example:

    <osgi:service interface="org.osgi.service.cm.ManagedService" ref="myManagedService">
       <osgi:service-properties>
         <entry key="service.pid" value="my.managed.service.pid"/>
       </osgi:service-properties>
    </osgi:service>

    <bean id="myManagedService" class="com.xyz.MyManagedService"/>

Prev | Home | Next
Chapter 10. Working With Bundles | Sponsored by SpringSource | Chapter 12. Testing OSGi based Applications