Building OSGi applications with the Blueprint Container specification

The Open Service Gateway initiative (OSGi) Alliance framework is becoming increasingly popular. It provides great mechanisms for developing modular and dynamic applications. The recent OSGi Service Platform Release 4 V4.2 specifications introduced the Blueprint Container specification. In this article, learn how the Blueprint Container provides a simple programming model for creating dynamic applications in the OSGi environment without adding complexity to the Java™ code. Numerous examples help get you started with the Blueprint XML file and the component XML definitions.

Share:

Jarek Gawor (jgawor@us.ibm.com), Advisory Software Engineer, IBM

Author photoJarek Gawor is an advisory software engineer for IBM in Research Triangle Park, North Carolina, in the Software Group. He is an Apache Geronimo committer and PMC member. He received a Master's Degree in Computer Science from Illinois Institute of Technology.



17 November 2009 (First published 27 October 2009)

Also available in Japanese

Introduction

The OSGi framework, which provides great mechanisms for developing modular and dynamic applications, has been growing in popularity. The recent OSGi Service Platform Release 4 V4.2 specifications introduced a specification called the Blueprint Container.

Spring dynamic modules

If you're familiar with the Spring framework, you'll notice many similarities between Spring and the Blueprint Container specification. The Blueprint specification is based on the Spring Dynamic Modules project.

The Blueprint Container specification defines a dependency injection framework for OSGi. It is designed to deal with the dynamic nature of OSGi, where services can become available and unavailable at any time. The specification is also designed to work with plain old Java objects (POJOs) so that the same objects can be used within and outside the OSGi framework. The Blueprint XML files that define and describe the various components of an application are key to the Blueprint programming model. The specification describes how the components get instantiated and wired together to form a running application.

The Blueprint Container specification uses an extender pattern, whereby an extender bundle monitors the state of bundles in the framework and performs actions on behalf of those bundles based on their state. The Blueprint extender bundle waits for the bundles to be activated and checks whether they are Blueprint bundles. A bundle is considered to be a Blueprint bundle when it contains one or more Blueprint XML files. These XML files are at a fixed location under the OSGI-INF/blueprint/ directory or are specified explicitly in the Bundle-Blueprint manifest header.

Once the extender determines that a bundle is a Blueprint bundle, it creates a Blueprint Container on behalf of that bundle. The Blueprint Container is responsible for:

  • Parsing the Blueprint XML files
  • Instantiating
  • Wiring the components together

During initialization, the Blueprint Container ensures that mandatory service references are satisfied, registers all the services into the service registry, and creates initial component instances. The Blueprint extender bundle also destroys the Blueprint Container for a bundle when the bundle is stopped.

This article focuses on the Blueprint XML. Learn, with several examples, about the component XML definitions and their use.


Blueprint XML

The Blueprint XML file is identified by a top-level blueprint element, as shown in Listing 1.

Listing 1. Blueprint XML file fragment
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns=”http://www.osgi.org/xmlns/blueprint/v1.0.0”>
    ...
</blueprint>

The Blueprint XML file contains definitions of various component managers. The Blueprint Container specification defines four main component managers: a bean manager, a service manager, and two service reference managers. Each manager is responsible for creating and managing the life cycle of the components they create. When asked, the managers provide a component instance. Each manager has a corresponding XML element that describes the manager properties. The managers can be top-level managers or inlined within other manager definitions. The managers also share some common attributes.

id
Defines the manager ID. The id attribute is optional. If it is not specified, a unique ID will be automatically generated and assigned to a top-level manager. The inlined managers are considered anonymous and do not allow for the id attribute to be set. The manager IDs must be unique for all top-level managers within the Blueprint Container. The IDs are used so managers can refer to each other. For example, during injection, the manager will ask the referenced managers to provide an object that will be injected into the component that the manager is creating.
activation
This optional attribute defines the activation mode for the manager. Two activation modes are supported:
  • eager, where the manager is activated during Blueprint Container initialization.
  • lazy, where the manager is activated on demand.
By default, eager activation mode is assumed. However, the default activation mode for all managers within the Blueprint XML file can be changed by setting the default-activation attribute on the blueprint element. A manager is activated when it is asked to provide its first component instance. A manager is deactivated when the Blueprint Container is being destroyed. Each manager has its own activation and deactivation steps.
dependsOn
This optional attribute specifies a list of manager IDs. The listed managers will be activated first, before the manager is activated. A manager can have explicit and implicit dependencies. The dependsOn attribute defines the explicit dependencies. The implicit dependencies are defined by the references to other managers within a manager definition.

Bean manager

A bean manager creates an instance of a Java object with the given arguments and properties. A bean manager can create single or multiple object instances depending on the scope settings. It can also manage the life cycle of an object and notify it when all properties have been injected or when it is being destroyed.

In Blueprint XML, a bean element defines a bean manager. The arguments used for object construction are specified by the argument elements; the injected properties are specified by the property sub-elements.

Signature disambiguation

The Blueprint specification defines a multiple-step algorithm for signature disambiguation. The algorithm considers all possible constructors and the arrangement of the parameters within each constructor to find the best match. The same algorithm is used with methods. Section 121.9.1 of the specification has more details.

During object construction, the Blueprint Container must first find the right constructor or a factory method with a compatible set of parameters that matches the arguments specified in the XML. By default, the Blueprint Container uses the number and order of the argument elements in XML to find the right constructor or method. If the argument elements cannot be mapped to the parameters in the order they are in, the Blueprint Container will attempt to reorder the argument elements and find the best-fitting arrangement.

To help the Blueprint Container pick the right constructor, method, or parameter arrangement, additional attributes, such as index or type, can be specified on the argument element. For example, the type attribute specifies a class name used to match the argument element to a parameter by the exact type.

The property element specifies the name and value of the property to inject. The property name corresponds to a setter method name in the Java class. For example, if the property name is foo, the corresponding setter method is setFoo(arg). The property names and corresponding setter method names follow the design pattern for properties as defined in the JavaBeans specification.

The value for the argument and property elements can be specified using a value or ref attribute, or it can be inlined. The ref attribute specifies the ID of a top-level manager, and is used to obtain an object from the referenced manager as the argument or property value. The inlined value can be any of the XML values described in the "Object values" section.

Construction

A bean can be constructed in three ways by using:

  • A class constructor
  • A static factory method
  • An instance factory method

Listings 2, 3, and 4 demonstrate three ways of constructing Java objects. Each listing shows a partial Java class and the corresponding Blueprint XML excerpt that drives the object creation.

Listing 2 shows a simple constructor creation example. In this example, the class attribute specifies the name of the Java class to instantiate. The Blueprint Container will create the Account object by passing 1 as the argument to the constructor and calling the setDescription() method to inject the description property.

Listing 2. Constructor example
   public class Account {      
       public Account(long number) {
          ...
       }
       public void setDescription(String description) {
          ...
       }
       public String getDescription() {
          ...
       }
   }

   <bean id=”accountOne” class=“org.apache.geronimo.osgi.Account”>
       <argument value=”1”/>
       <property name=”description” value=”#1 account”/>
   </bean>

Listing 3 shows a static factory method construction. In this example, the class attribute specifies the name of the class that contains a static factory method. The name of the static factory method is specified by the factory-method attribute. The Blueprint Container will call the createAccount() static method on the AccountFactory class and pass 2 as the argument to create the Account object. Once the factory returns the created object, the container will inject it with the description property.

Listing 3. Static factory method example
   public class StaticAccountFactory {      
       public static Account createAccount(long number) {
          return new Account(number);
       }
   }

   <bean id=”accountTwo” class=“org.apache.geronimo.osgi.StaticAccountFactory” 
         factory-method=“createAccount”>   
       <argument value=”2”/>
       <property name=”description” value=”#2 account”/>     
   </bean>

With an instance factory method construction, as shown in Listing 4, two managers are used. One manager is a factory, and the other uses the factory to create an object. The factory-ref attribute is used to specify the ID of a top-level bean or a reference manager that acts like a factory. The provided factory object must have a factory method as specified by the factory-method attribute.

In the example, the accountFactory bean manager is the factory. The Blueprint Container will first create the AccountFactory instance with its own arguments and properties. In this case, only a single argument is specified: the factory name. The Blueprint Container will then call the createAccount() method on the AccountFactory instance and pass 3 as the argument to create the Account object. Once the factory returns the created object, the container will inject it with the description property.

Listing 4. Instance factory method example
   public class AccountFactory {      
       public AccountFactory(String factoryName) {
          ...
       }
       public Account createAccount(long number) {
          return new Account(number);
       }
   }

   <bean id=”accountFactory” class=“org.apache.geronimo.osgi.AccountFactory”>  
       <argument value=”account factory”/>      
   </bean>

   <bean id=”accountThree”
         factory-ref=“accountFactory” 
         factory-method=“createAccount”>   
       <argument value=”3”/>
       <property name=”description” value=”#3 account”/>      
   </bean>

Scope

Depending on the scope setting, a bean manager can create single or multiple object instances. The Blueprint Container specification defines two main scopes:

singleton
The bean manager creates a single instance of the bean and returns that instance every time the manager is asked to provide an object.
prototype
The bean manager creates a new instance of the bean every time the manager is asked to provide an object.

By default, the singleton scope is assumed for top-level bean managers. The scope attribute cannot be set on an inlined bean manager, so the inlined managers are always considered to have prototype scope.

The scope attribute is used to specify the scope settings. Listing 5 shows two bean definitions with different scope settings.

Listing 5. Scope examples
   <bean id=”prototypeAccount” class=“org.apache.geronimo.osgi.Account” 
         scope=”prototype”>
       <argument value=”4”/>
   </bean>

   <bean id=”singletonAccount” class=“org.apache.geronimo.osgi.Account” 
         scope=”singleton”>
       <argument value=”5”/>
   </bean>

Life-cycle callbacks

A bean manager can also manage the life cycle of the object it creates and can notify it when all properties have been injected or when it is being destroyed. The Blueprint Container specification defines two callback methods:

init-method
Specifies a method to be called once all the properties have been injected.
destroy-method
Specifies a method to be called when the Blueprint Container is destroying the object instance.

The destroy-method callback is not supported for beans in the prototype scope. It is the responsibility of the application to destroy those instances. Both life-cycle methods must be public, take no arguments, and return no value.

Listing 6 shows an example of a Java class with life-cycle methods and a Blueprint XML bean entry that specifies the init-method and destroy-method attributes.

Listing 6. Life-cycle callback example
   public class Account {      
       public Account(long number) {
          ...
       }
       public void init() {
          ...
       }
       public void destroy() {
          ...
       }
   }

   <bean id=”accountFour” class=“org.apache.geronimo.osgi.Account” 
         init-method=”init” destroy-method=”destroy”>
       <argument value=”6”/>
       <property name=”description” value=”#6 account”/>
   </bean>

Service reference managers

Service reference managers provide access to the services registered in the OSGi service registry. There are two service reference managers defined by the Blueprint specification: reference and reference list.

Reference manager

The reference manager provides an object that is a proxy to the actual service registered in the service registry. A proxy allows the injected object to remain the same while the backing service can come and go or be replaced with another service. Calls on a proxy that does not have a backing service will block until a service becomes available or a timeout occurs.

The reference manager is defined by a reference element. The amount of time a proxy will wait for a backing service to be available is specified using the timeout attribute. If the timeout attribute is not specified, the default timeout of five minutes is assumed. The default timeout can also be changed for all reference managers in the Blueprint XML file using the default-timeout attribute on the blueprint element. All timeout values are specified in milliseconds; a value of 0 means indefinite timeout.

Listing 7 shows a simple reference manager example. The service proxy will have a 30-second timeout.

Listing 7. Reference manager example
   <reference id=”serviceReferenceOne” 
              interface=”java.io.Serializable” 
              timeout=”30000”/>

Reference-list manager

The reference-list manager provides a List object that contains the service proxy objects or ServiceReference objects, depending on the member type setting. The provided List object is dynamic, as it can grow and shrink as matching services are added or removed from the service registry. The List object is read-only and supports only a subset of the List API.

The proxies in a reference-list manager are different from the proxies in a reference manger. They have a fixed backing service, do not have a timeout, and throw ServiceUnavailableException immediately if the backing service becomes unavailable.

The reference-list manager is defined by a reference-list element. The type of the members in the provided List object is specified using the member-type attribute. The member-type attribute supports two values:

service-object
Injects a list of service proxy objects, assumed by default.
service-reference
Injects a list of ServiceReference objects.

Listing 8 shows a simple reference-list manager example. The List members will be service proxies.

Listing 8. Reference-list manager example
   <reference-list id=”serviceReferenceListOne” 
                   interface=”java.io.Serializable” 
                   member-type=”service-object”/>

Service selection and proxies

The reference and reference-list managers share several attributes. Three shared attributes are used for service selection: interface, component-name and a filter.

You can use the interface attribute to specify an interface class. The interface class is used for two purposes: for service selection and for service proxies. The interface attribute is optional, but if set, it must specify an interface class. For service selection, the interface class is used to select services from the service registry registered with that interface name. For service proxies, the proxies returned by service reference managers must implement all the methods defined by that interface class. If the interface attribute is not specified, the proxy behaves as if it implements an interface without any methods.

You can also use the component-name and filter attributes for service selection. The component-name attribute is just a convenient way of adding an osgi.service.blueprint.compname=<component-name> expression to the selection filter. Similarly, the filter attribute specifies the raw OSGi filter expression to be added to the selection filter. The interface, component-name, and filter attributes are combined to create one main OSGi filter expression used for the service selection.

For example, the selection filter for the reference in Listing 7 is (&(objectClass=java.io.Serializable)), while the selection filter for the reference in Listing 9 is (&(objectClass=java.io.Serializable)(osgi.service.blueprint.compname=myAccount)(mode=shared)).

Listing 9. Service selection example
   <reference id=”serviceReferenceTwo”              
              interface=”java.io.Serializable” 
              component-name=”myAccount”
              filter=”(mode=shared)”/>

Availability

A service reference manager can require that at least one service that matches its selection criteria must exist before the Blueprint Container initialization can continue. That requirement is controlled with the availability attribute. The availability attribute can have two values:

optional
Services matching the selection criteria may or may not exist.
mandatory
At least one service matching the selection criteria must exist.

By default, mandatory availability is assumed. The default availability setting can be changed for all service reference managers in the Blueprint XML using a default-availability attribute on the blueprint element.

A service reference manager with mandatory availability that has a matching service is considered satisfied. A service reference manager with optional availability is always considered satisfied even if it does not have any matching services. The Blueprint Container initialization will be delayed until all mandatory service reference managers are satisfied.

It's important to understand that mandatory availability is only considered during Blueprint Container initialization. After initialization, the mandatory service reference can become unsatisfied as services come and go at any point.

Listing 10 shows an example of a reference manager with mandatory availability.

Listing 10. Availability example
   <reference id=”serviceReferenceThree” 
              interface=”java.io.Serializable” 
              timeout=”30000” 
              availability=”mandatory”/>

Reference listener

Both service reference managers can have zero or more reference listeners. Reference listeners are objects that have callback methods invoked when the service is selected by the service reference manager or when the service is no longer used by the service reference manager. A reference listener is specified using the reference-listener element. The bind-method and unbind-method attributes specify the callback methods. The object that provides the callback methods can be inlined within the reference-listener element or specified as a reference to a top-level manager.

Both bind and unbind callback methods can have any of the following signatures. (anyMethod represents an arbitrary method name.)

void anyMethod(ServiceReference)
The argument is a ServiceReference object of the service being bound or unbound.
void anyMethod(? super T)
The argument is the service object proxy being bound or unbound. The type T must be assignable from the service object.
void anyMethod(? super T, Map)
The first argument is the service object proxy being bound or unbound. The type T must be assignable from the service object. The second argument provides the service properties associated with the service.

If a reference listener has multiple overloaded methods for a callback, every method with a matching signature is invoked.

For a reference-list manager, the listener callbacks are invoked each time a matching service is added or removed from the service registry. However, for a reference manager, the bind callback will not be invoked when the manager is already bound to a service and a matching service with lower ranking is added to the service registry. Similarly, the unbind callback will not be called when the service the manager is bound to goes away and it can be immediately replaced with another matching service.

It's important to understand that when using a reference manager and interacting with stateful services, you should use reference listeners to track the backing services of the proxy in order to manage the state of the service appropriately.

Listing 11 shows a simple registration listener example. The ReferenceListener class has two bind and one unbind callback methods, which will be called as the services are bound and unbound from the service reference-list manager.

Listing 11. Reference-listener example
   public class ReferenceListener {
       public void bind(ServiceReference reference) {
           ...
       }
       public void bind(Serializable service) {
           ...
       }
       public void unbind(ServiceReference reference) {
           ...
       }       
   }

   <reference-list id=”serviceReferenceListTwo” interface=”java.io.Serializable”
              availability=”optional”>
      <reference-listener 
              bind-method=”bind” unbind-method=”unbind”>
          <bean class=“org.apache.geronimo.osgi.ReferenceListener”/>        
      </reference-listener>
   </reference-list>

Service manager

A service manager registers a service in the OSGi service registry. The service manager registers and unregisters the service if all the mandatory service reference managers in its dependencies are satisfied. Since the mandatory service references can become unsatisfied at any point, a service manager returns a ServiceRegistration proxy object that delegates the calls to the actual ServiceRegistration object.

During initialization, a Blueprint Container registers ServiceFactory-based services for each service manager in the Blueprint Container instead of the actual service objects. These services allow the Blueprint Container to delay the object creation as they intercept the service requests and instantiate the actual service object only when needed. The actual service object is provided by another manager, usually a bean manager. The actual service object can implement the OSGi ServiceFactory interface.

In Blueprint XML, a service element defines a service manager. The manager that provides the service object can be referenced using the ref attribute or be inlined within the service element. Listing 12 shows two services: one with a referenced and one with an inlined manager.

Listing 12. Service-manager examples
   <service id=”serviceOne” ref=”account” ... />

   <service id=”serviceTwo” … >
      <bean class=“org.apache.geronimo.osgi.Account”>
          <argument value=”123”/>
      </bean>
   </service>

Service interfaces

Each service must be registered under one or more interface names. The list of the interface names for the service can be specified explicitly or determined automatically from the service object based on the auto-export setting. The interface names can be set explicitly using either:

  • interface attribute, which can only specify a single interface name.
  • interfaces sub-element, which allows any number of interfaces to be set.

The auto-export setting is specified by the auto-export attribute and supports the four options below.

disabled
The default value if the auto-export attribute is not specified. The list of interfaces must be specified using the interface attribute or interfaces sub-elements.
interfaces
Register the service using all public interfaces implemented by the service class and any of its super classes.
class-hierarchy
Register the service using the service class and any of its public super classes.
all-classes
Combines interfaces and class-hierarchy options.

Listing 13 shows services with three ways of specifying the service interfaces. In this example, serviceOne and serviceTwo services are registered with a single Serializable interface class, while serviceThree service is registered with MyAccount, Account, and Serializable classes.

Listing 13. Service interface examples
   public class MyAccount extends Account implements java.io.Serializable {
       ...
   }

   <bean id=”myAccount” class=”org.apache.geronimo.osgi.MyAccount”>
       <argument value=”7”/>
       <property name=”description” value=”MyAccount”/> 
   </bean>

   <service id=”serviceOne” ref=”myAccount” interface=”java.io.Serializable”/>

   <service id=”serviceTwo” ref=”myAccount”>
      <interfaces>
          <value>java.io.Serializable</value>
      </interfaces>
   </service>

   <service id=”serviceThree” ref=”myAccount” autoExport=”all-classes”/>

Service properties

A service can also be registered with a set of properties that can be specified using the service-properties sub-element. The service-properties element contains multiple entry sub-elements that represent the individual properties. The property key is specified using a key attribute, but the property value can be specified as a value attribute or inlined within the element. The service property values can be of different types, but only primitives, primitive wrapper classes, collections, or arrays of primitive types are allowed.

Listing 14 shows an example of a service registration with two service properties. The active service property has a value of java.lang.Boolean type. The mode property is of String type.

Listing 14. Service properties examples
   <service id=”serviceFour” ref=”myAccount” autoExport=”all-classes”>
      <service-properties>
          <entry key=”mode” value=”shared”/>
          <entry key=”active”>
              <value type=”java.lang.Boolean”>true</value>
          </entry>
      </service-properties>
   </service>

An osgi.service.blueprint.compname property is automatically added to the service properties if the manager that provides the service object for the service is a top-level manager. The value of the osgi.service.blueprint.compname property is the ID of the top-level manager that provides the service instance. For example, given the service example in Listing 14, the value of osgi.service.blueprint.compname property would be set to myAccount.

Service ranking

You can use the ranking attribute to expose the service with a specific ranking. If the ranking attribute is not specified, the service will be registered without a ranking. In such cases, the OSGi framework assumes 0 as the default ranking for the service.

An example of service registration with a ranking is shown below.

Listing 15. Service ranking example
   <service id=”serviceFive” ref=”myAccount” auto-export=”all-classes” ranking=”3”/>

Registration listener

A service manager can have zero or more registration listeners, which are objects that have callback methods invoked right after the service is registered or right before the service is unregistered. A registration listener is specified using the registration-listener sub-element. The registration-method, and unregistration-method attributes specify the callback methods. The object that provides the callback methods can be inlined within the registration-listener element, or be specified as a reference to a top-level manager.

The signature for the registration and unregistration callback methods depends on whether the service object implements the ServiceFactory interface. If the service implements the ServiceFactory interface, both methods must have a void anyMethod(ServiceFactory, Map) signature, where anyMethod represents an arbitrary method name.

If the service does not implement the ServiceFactory interface, both callback methods must match the void anyMethod(? super T, Map) signature, where the type T is assignable from the service object's type. The first argument to the callback method is an instance of the service object, and the second argument is the registration properties. If a registration listener has multiple overloaded methods for a callback, then every method with a matching signature is invoked.

Listing 16 shows a simple registration listener example.

Listing 16. Registration listener example
   public class RegistrationListener {
       public void register(Account account, Map properties) {
           ...
       }
       public void unregister(Account account, Map properties) {
           ...
       }
   }

   <service id=”serviceSix” ref=”myAccount” auto-export=”all-classes”>
      <registration-listener 
              registration-method=”register” unregistration-method=”unregister”>
          <bean class=“org.apache.geronimo.osgi.RegistrationListener”/>         
      </registration-listener>
   </service>

Environment managers

The Blueprint Container specification also defines a number of special environmental managers that have set IDs and provide access to the environmental components. They have no XML definition and cannot be overridden, since their IDs are reserved and may not be used with other managers. The objects provided by environment managers can only be injected into other managers using a reference. The Blueprint Container specification defines four environment managers:

blueprintBundle
Provides bundle's Bundle object.
blueprintBundleContext
Provides bundle's BundleContext object.
blueprintContainer
Provides the BlueprintContainer object for the bundle.
blueprintConverter
Provides the Converter object for the bundle that provides access to the Blueprint Container type conversion facility. Type conversion has more information.

Listing 17 shows a simple example where the Bundle object provided by the blueprintBundle environmental manager is injected into the accountManagerOne bean.

Listing 17. Environment manager example
   public class AccountManager {
       public void setManagerBundle(Bundle bundle) {
           ...
       }
   }

   <bean id=”accountManagerOne” class=”org.apache.geronimo.osgi.AccountManager”>
      <property name=”managerBundle” ref=”blueprintBundle”/>
   </bean>

Object values

The Blueprint Container specification defines many XML elements that describe different types of object values. These XML value elements are used within the manager definitions. For example, they can be used in a bean manager to specify argument or property values, or in a service manager to specify the service properties' values. The XML value elements are converted into the actual value objects and injected into the manager components.

The ref element defines a reference to a top-level manager. The component-id attribute specifies an ID of a top-level manager. The injected value will be the object returned by the referenced manager.

Listing 18 shows an example of the ref value element. The accountOne bean instance is injected into the managedAccount property of the accountManagerTwo bean.

Listing 18. Reference value example
   public class AccountManager {
       ...
       public void setManagedAccount(Account account) {
           ...   
       }
   }

   <bean id=”accountOne” class=“org.apache.geronimo.osgi.Account”>
       <argument value=”1”/>
       <property name="description" value="#1 account"/>
   </bean>

   <bean id=”accountManagerTwo” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”managedAccount”>
           <ref component-id=”accountOne”/>
       </property>
   </bean>

The idref element defines an ID of a top-level manager. The injected value is the component-id as specified by the component-id attribute. The idref element is used to ensure that the manager of the specified ID actually exists before the manager is activated.

The value element represents an object to be created from the string content of the element. You can use the optional type attribute to specify a type into which the string content should be converted. If the type attribute is not specified, the string content will be converted into the type it is being injected into.

The null element represents Java null.

The list, set, and array elements are collections and represent a java.util.List object, java.util.Set object, and Object[] array, respectively. The sub-elements of these collections can be any of the XML value elements described in this section. The optional value-type attribute can be set on these elements to specify a default type for the collection sub-elements.

The example in Listing 19 shows how the XML value elements can be combined to create a list. The created list will contain the following four items:

  • A “123” String
  • A java.math.BigInteger object with 456 value
  • A null
  • A java.util.Set object with two values of type java.lang.Integer
Listing 19. Complex list value example
   <list>
       <value>123</value>
       <value type=”java.math.BigInteger”>456</value>
       <null/>
       <set value-type=”java.lang.Integer”>
           <value>1</value>
           <value>2</value>
       </set>      
   </list>

The props element represents a java.util.Properties object where the keys and values are of String type. The prop sub-elements represent the individual properties. The property key is specified using a key attribute, but the property value can be specified as a value attribute or as a content of the element.

Listing 20 shows an example of the props value element.

Listing 20. Properties value example
    <props>
        <prop key=”yes”>good</prop>
        <prop key=”no” value=”bad”/>       
    </props>

The map element represents a java.util.Map object where the keys and the values can be arbitrary objects. The entry sub-elements represent the individual properties. The key can be specified as a key attribute, key-ref attribute, or inlined within a key sub-element. The value can be specified as a value attribute, value-ref attribute, or be inlined. The inlined value can be specified as any of the XML value elements described in this section. However, the inlined key can be specified as any of the XML value elements except the null element. Null keys are not allowed in map elements in the Blueprint Specification. The key-ref and value-ref attributes specify an ID of a top level manager and are used to obtain an object from the specified manager as the property key or value. The map element can specify key-type and value-type attributes to define a default type for keys and values.

Listing 21 shows an example of the map value element. It also shows how the entries of a map object can be constructed in several ways. The created map object will contain the following entries:

  • A myKey1 String key that is mapped to myValue String.
  • A key that is an object returned by account bean manager is mapped to myValue String.
  • A key that is a java.lang.Integer object with 123 value is mapped to myValue String.
  • A myKey2 String key is mapped to a value that is an object returned by account bean manager.
  • A myKey3 String key is mapped to a value that is a java.lang.Long object with 345 value.
  • A key that is a java.net.URI object with urn:ibm value is mapped to a value which is a java.net.URL object with http://ibm.com value.
Listing 21. map value example
   <map>
       <entry key=”myKey1” value=”myValue”/>

       <entry key-ref=”account” value=”myValue”/>
       <entry value=”myValue”>
           <key>
               <value type=”java.lang.Integer”>123</value>
           <key/>
       </entry>

       <entry key=”myKey2” value-ref=”account”>
       <entry key=”myKey3”>           
           <value type=”java.lang.Long”>345</value>          
       </entry>

       <entry> 
           <key>
               <value type=”java.net.URI”>urn:ibm</value>
           <key/>
           <value type=”java.net.URL”>http://ibm.com</value>
       </entry>
   </map>

Each manager can also be inlined as a value. Listing 22 shows an inlined bean manager example.

Listing 22. Inlined manager value example
   <bean id=”accountManagerThree” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”managedAccount”>
           <bean class=“org.apache.geronimo.osgi.Account”>
               <argument value=”10”/>
               <property name="description" value="Inlined Account"/>
           </bean>
       </property>
   </bean>

Type conversion

During injection, the Blueprint Container converts the XML value elements into actual objects. It converts the elements based on the type of the injected property. For example, in Listing 2, the Blueprint Container converts the 123 String value into a long value. The Blueprint Container provides a number of built-in conversions, such as converting:

  • String values into all primitive types, wrapper types, or any types that have a public constructor that takes a String value.
  • array elements into collection objects (with compatible member types).
  • list or set elements into array objects (with compatible member types).

The Blueprint Container also supports generics. If the generics information is available, the Blueprint Container will use that information to perform the conversions. For example, in Listing 23 the list element will be converted into a list of java.util.Long objects.

Listing 23. Generics conversion example
   public class AccountManager {      
       ...
       public void setAccountNumbers(List<Long> accounts) {
          ...
       }
   }

   <bean id=”accountManagerFour” class=“org.apache.geronimo.osgi.AccountManager”>
       <property name=”accountNumbers”>
           <list>
               <value>123</value>
               <value>456</value>
               <value>789</value>
           </list>
       </property>
   </bean>

In addition to the built-in conversions, a Blueprint bundle can provide its own converters. The custom converters are bean managers that provide an object that implements Blueprint's Converter interface. The custom converters are specified within the type-converters element under the blueprint element. The type converters are initialized first during Blueprint Container initialization so other managers can take advantage of the custom converters. The Blueprint Container specification has more information about writing custom converters.


Experimenting with Blueprint

To experiment with Blueprint applications, you need two things: an OSGi platform and the Blueprint Container implementation. In this article, we will use Equinox as the OSGi platform, but others — such as Apache Felix — would work just as well. For the Blueprint Container, we will use an implementation from the Apache Aries incubator project. The Blueprint implementation in Aries was originally developed at the Apache Geronimo project, but has been moved to Aries, where it is being actively developed.

The attached sample provides a good starting point for experimenting with Blueprint. It contains two modules: blueprint-sample and blueprint-assembly. The blueprint-sample module is a sample Blueprint bundle. It contains many of the Java classes and Blueprint XML definitions shown in this article. The blueprint-assembly module packages the Equinox framework, the Apache Aries Blueprint implementation, and the sample bundle together in an easy-to-start container.

Building the sample

Download and unzip the attached sample source to a directory of your choice. Use Apache Maven to build the sample source. Execute the commands in Listing 24 to build the sample.

Listing 24. Building the sample
cd sample
mvn install

Maven will automatically build both modules in the sample. Once the entire sample is successfully built, the target directory of the blueprint-assembly module will contain a number of JAR files. It will contain the Apache Aries Blueprint implementation, the sample bundle and a couple other JARs that provide logging capabilities for the OSGi framework. It will also contain the osgi-3.5.0.v20090520.jar file, which provides the Equinox framework. Once started, the Equinox framework will automatically install and start all the other JARs in the target directory. To start the Equinox framework, execute the commands in Listing 25.

Listing 25. Starting Equinox
cd blueprint-assembly/target
java -jar osgi-3.5.0.v20090520.jar -console

The Equinox console will appear after successful startup. Use the ss command to display the installed bundles; Figure 1 shows the output of the ss command.

Figure 1. Installed bundles output
The Equinox console appears after successful startup

Running the sample bundle

The sample bundle will be automatically installed in Equinox framework, but will not be started. To start the sample bundle, execute the start 5 command in the Equinox console; the number 5 is the ID of the org.apache.aries.sample_1.0.0.SNAPSHOT sample bundle. Once the sample bundle is successfully started, you should see the following output in the console, as shown in Figure 2.

Figure 2. Sample bundle output
Once the sample bundle is successfully started, this output will appear in the console

Summary

The Blueprint Container specification, introduced in the latest OSGi specification, provides a simple and easy programming model for creating dynamic applications in the OSGi environment without adding complexity to the Java code. With the Aries Blueprint Container implementation, you can start building Blueprint-based applications today.


Download

DescriptionNameSize
Sample sourceos-osgiblueprint-sample.zip11KB

Resources

Learn

  • Check out JavaWorld's OSGi Bundles for beginners tutorial. Learn how to create, execute, and manage bundles in an OSGi container.
  • Read more about dependency injection.
  • Learn more about the OSGi Alliance and get the latest news, events, forums, specifications. and more.
  • Apache Geronimo is producing a server runtime framework that pulls together open source alternatives to create runtimes that meet the needs of developers and system administrators.
  • Learn all about Apache Felix.
  • Get an overview of Apache Aries.
  • The property names and corresponding setter method names follow the design pattern for properties as defined in the JavaBeans specification.
  • Learn how Spring Dynamic Modules make it easy to build Spring applications that run in an OSGi framework.
  • To listen to interesting interviews and discussions for software developers, check out developerWorks podcasts.
  • Stay current with developerWorks' Technical events and webcasts.
  • Follow developerWorks on Twitter.
  • Check out upcoming conferences, trade shows, webcasts, and other Events around the world that are of interest to IBM open source developers.
  • Visit the developerWorks Open source zone for extensive how-to information, tools, and project updates to help you develop with open source technologies and use them with IBM's products, as well as our most popular articles and tutorials.
  • Watch and learn about IBM and open source technologies and product functions with the no-cost developerWorks On demand demos.

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Open source on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, XML
ArticleID=438918
ArticleTitle=Building OSGi applications with the Blueprint Container specification
publish-date=11172009