Blueprint

Introduction

Blueprint provides a dependency injection framework for OSGi and was standardized by the OSGi Alliance in OSGi Compendium R4.2. 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) enabling simple components to be written and unit tested in a JSE environment without needing to be aware of how they are assembled. The Blueprint XML files that define and describe the assembly of various components are key to the Blueprint programming model. The specification describes how the components get instantiated and wired together to form a running module.

The following documentation covers the 80:20 usage of Blueprint. For further details, please refer to the OSGi Compendium R4.2 specification.

Blueprint Bundles

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 the components

  • Wiring the components together

  • Registering services

  • Looking up service references

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.

Blueprint XML

The Blueprint XML file is identified by a top-level blueprint element, as shown below:

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
    ...
</blueprint>

The XML namespace identifies the document as conforming to the Blueprint version 1.0.0. The top-level blueprint element identifies the document as a blueprint module definition.

TODO: ensure id, activation and dependsOn get documented somewhere.

Beans

Beans are declared using the bean element. The following defines a single bean called accountOne implemented by the POJO org.apache.aries.simple.Account.

<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
   <bean id="accountOne" class="org.apache.aries.simple.Account" />
</blueprint>

Bean Construction

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.

A bean can be constructed using a class constructor. In the following 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.

   :::java
   public class Account {
       public Account(long number) {
          ...
       }
       ...
   }



   <bean id="accountOne" class="org.apache.aries.simple.Account">
       <argument value="1"/>
   </bean>

A bean can be constructed using a static factory method. 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 StaticAccountFactory class and pass 2 as the argument to create the Account object.

   public class StaticAccountFactory {
       public static Account createAccount(long number) {
      return new Account(number);
       }
   }



   <bean id="accountTwo"
    class="org.apache.aries.simple.StaticAccountFactory"
     factory-method="createAccount">
       <argument value="2"/>
   </bean>

A bean can be constructed using an instance factory method. In the example, the accountFactory bean 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.

public class AccountFactory { + public AccountFactory(String factoryName) { …​ } public Account createAccount(long number) { return new Account(number); } }

   <bean id="accountFactory"
    class="org.apache.aries.simple.AccountFactory">
       <argument value="account factory"/>
   </bean>

   <bean id="accountThree"
     factory-ref="accountFactory"
     factory-method="createAccount">
       <argument value="3"/>
   </bean>

Bean Properties

Beans can have property values injected. Injection is performed immediately after the bean is constructed. The following example creates the Account bean and then sets the description property using the Java Beans naming convention.

public class Account { + public Account(long number) { …​ } public String getDescription() { …​ } }

<bean id="accountOne" class="org.apache.aries.simple.Account">
    <argument value="1"/>
    <property name="description" value="#1 account"/>
</bean>

Bean Wiring

Property injection is used for wiring beans together. In the following example accountOne is injected with a Currency bean.

   public class Account {
       public Account() {
      ...
       }
       public void setCurrency(Currency currency) {
      ...
       }
   }



   public class Currency {
       public Currency() {
      ...
       }
   }



   <bean id="accountOne" class="org.apache.aries.simple.Account">
       <property name="currency" ref="currency" />
   </bean>

   <bean id="currency" class="org.apache.aries.simple.Currency" />

Services

In Blueprint XML, a service element defines the registration of a service in the OSGi service registry.

The bean that provides the service object can be referenced using the ref attribute. The interfaces under which the service is registered can be specified using the interface attribute:

   public class AccountImpl implements Account {
       public Account() {
      ...
       }
       public void setCurrency(Currency currency) {
      ...
       }
   }



   <service id="serviceOne" ref="account"
    interface="org.apache.aries.simple.Account" />

   <bean id="account" class="org.apache.aries.simple.AccountImpl" />

The bean that provides the service object can be inlined in the service element as follows:

<service id="serviceTwo"  interface="org.apache.aries.simple.Account">
   <bean class="org.apache.aries.simple.AccountImpl" />
</service>

The interfaces under which a service is registered can be determined by Blueprint using auto-export. The following registers the service under all the bean’s interfaces:

   <service id="serviceOne" ref="account" auto-export="interfaces" />

   <bean id="account" class="org.apache.aries.simple.AccountImpl" />

Other values for auto-export are disabled (the default) class-hierarchy and 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 OSGi service property types are permitted: primitives, primitive wrapper classes, collections, or arrays of primitive types.

The following is an example of a service registration with two service properties. The active service property has type of java.lang.Boolean. The mode property is of the default type, String.

<service id="serviceFour" ref="account" autoExport="all-classes">
   <service-properties>
   <entry key="active">
       <value type="java.lang.Boolean">true</value>
   </entry>
   <entry key="mode" value="shared"/>
   </service-properties>
</service>

Service Ranking

Service ranking can be used to affect the choice of service when there are multiple matches. When choosing between two services, the higher ranked service will be returned ahead of the lower. The default ranking value is

  1. Service ranking is specified using the ranking attributes as follows:

    <service id="serviceFive" ref="account" auto-export="all-classes"
     ranking="3" />

References

Services are found in the service registry using the reference element. The following shows a reference named accountRef to an Account service. If a service matching this reference is found in the service registry then it is set on the accountClient bean through the account property.

   <bean id="accountClient" class="...">
       <property name="account" ref="accountRef" />
   </bean>

   <reference id="accountRef" interface="org.apache.aries.simple.Account"
/>

Reference Dynamism

The object that is injected for a reference is actually a proxy to the service registered in the service registry. A proxy enables 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 at which point a ServiceUnavailableException will be thrown.

try {
   balance = account.getBalance();
} catch (ServiceUnavailableException e) {
   ...
}

The default timeout Blueprint will wait for is 300000 milliseconds (5 minutes). This value can be changed on a per bundle basis using directives on the Bundle-SymbolicName. The following switches the timeout off completely (the default is true):

Bundle-SymbolicName: org.apache.aries.simple.account;
 blueprint.graceperiod:=false

The following sets the timeout to 10000 milliseconds (10 seconds):

Bundle-SymbolicName: org.apache.aries.simple.account;
 blueprint.graceperiod:=false; blueprint.timeout=10000;

The timeout can also be set on an individual reference using the timeout attribute. The following sets the timeout for the account reference to 20000 milliseconds (20 seconds).

<reference id="accountRef" timeout="20000"
 interface="org.apache.aries.simple.Account" />

In all cases, a value of 0 means wait indefinitely for the reference to become satisfied.

Reference Lists

Multiple matching services can be found using the reference-list element. The reference-list 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 only supports a subset of the List API.

The proxies in a reference-list are different from the proxies for a reference. The reference-list proxies target a specific service, do not have a timeout, and throw ServiceUnavailableException immediately if their service becomes unavailable.

The following example shows a reference-list that returns a list of service objects (proxies). This is the default value for the member-type attribute

<reference-list id="accountRefs" member-type="service-object"
 interface="org.apache.aries.simple.Account" />

The following shows an example of a reference-list that returns a list of ServiceReferences:

<reference-list id="accountRefs" member-type="service-reference"
 interface="org.apache.aries.simple.Account" />

Example showing mandatory or optional references (availability)

Example showing use of filter

Bean Properties

Example showing use of bean properties

Scopes

Example showing singleton scope

Example showing prototype scope for beans

Example showing prototype scope for services

Object Values

Intro to Object Values

Examples showing the use of the various different object value types - ref, map, props collection (list, array, set).

Lifecycle

Example showing use of init/destroy-method

Lazy and Eager Activiation

Example showing lazy activiation.

Example showing eager activation.

Dynamism

Example showing service-listener

Example showing reference-listener

Type Converters