LibraryLink ToToggle FramesPrintFeedback

Importing a Service

This section describes how to obtain and use references to OSGi services that have been exported to the OSGi service registry. Essentially, you can use either the reference element or the reference-list element to import an OSGi service. The key difference between these elements is not (as you might at first be tempted to think) that reference returns a single service reference, while reference-list returns a list of service references. Rather, the real difference is that the reference element is suitable for accessing stateless services, while the reference-list element is suitable for accessing stateful services.

The following models for obtaining OSGi services references are supported:

A reference manager instance is created by the blueprint reference element. This element returns a single service reference and is the preferred approach for accessing stateless services. Figure 9.1 shows an overview of the model for accessing a stateless service using the reference manager.


Beans in the client blueprint container get injected with a proxy object (the provided object), which is backed by a service object (the backing service) from the OSGi service registry. This model explicitly takes advantage of the fact that stateless services are interchangeable, in the following ways:

  • If multiple services instances are found that match the criteria in the reference element, the reference manager can arbitrarily choose one of them as the backing instance (because they are interchangeable).

  • If the backing service disappears, the reference manager can immediately switch to using one of the other available services of the same type. Hence, there is no guarantee, from one method invocation to the next, that the proxy remains connected to the same backing service.

The contract between the client and the backing service is thus stateless, and the client must not assume that it is always talking to the same service instance. If no matching service instances are available, the proxy will wait for a certain length of time before throwing the ServiceUnavailable exception. The length of the timeout is configurable by setting the timeout attribute on the reference element.

A reference list manager instance is created by the blueprint reference-list element. This element returns a list of service references and is the preferred approach for accessing stateful services. Figure 9.2 shows an overview of the model for accessing a stateful service using the reference list manager.


Beans in the client blueprint container get injected with a java.util.List object (the provided object), which contains a list of proxy objects. Each proxy is backed by a unique service instance in the OSGi service registry. Unlike the stateless model, backing services are not considered to be interchangeable here. In fact, the lifecycle of each proxy in the list is tightly linked to the lifecycle of the corresponding backing service: when a service gets registered in the OSGi registry, a corresponding proxy is synchronously created and added to the proxy list; and when a service gets unregistered from the OSGi registry, the corresponding proxy is synchronously removed from the proxy list.

The contract between a proxy and its backing service is thus stateful, and the client may assume when it invokes methods on a particular proxy, that it is always communicating with the same backing service. It could happen, however, that the backing service becomes unavailable, in which case the proxy becomes stale. Any attempt to invoke a method on a stale proxy will generate the ServiceUnavailable exception.

The simplest way to obtain a stateles service reference is by specifying the interface to match, using the interface attribute on the reference element. The service is deemed to match, if the interface attribute value is a super-type of the service or if the attribute value is a Java interface implemented by the service (the interface attribute can specify either a Java class or a Java interface).

For example, to reference a stateless SavingsAccount service (see Example 9.1), define a reference element as follows:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference id="savingsRef"
             interface="org.fusesource.example.SavingsAccount"/>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAccount" ref="savingsRef"/>
  </bean>

</blueprint>

Where the reference element creates a reference manager bean with the ID, savingsRef. To use the referenced service, inject the savingsRef bean into one of your client classes, as shown.

The bean property injected into the client class can be any type that is assignable from SavingsAccount. For example, you could define the Client class as follows:

package org.fusesource.example.client;

import org.fusesource.example.SavingsAccount;

public class Client {
    SavingsAccount savingsAccount;
    
    // Bean properties
    public SavingsAccount getSavingsAccount() {
        return savingsAccount;
    }

    public void setSavingsAccount(SavingsAccount savingsAccount) {
        this.savingsAccount = savingsAccount;
    }
    ...
}

The simplest way to obtain a stateful service reference is by specifying the interface to match, using the interface attribute on the reference-list element. The reference list manager then obtains a list of all the services, whose interface attribute value is either a super-type of the service or a Java interface implemented by the service (the interface attribute can specify either a Java class or a Java interface).

For example, to reference a stateful SavingsAccount service (see Example 9.1), define a reference-list element as follows:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference-list id="savingsListRef"
                  interface="org.fusesource.example.SavingsAccount"/>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAccountList" ref="savingsListRef"/>
  </bean>

</blueprint>

Where the reference-list element creates a reference list manager bean with the ID, savingsListRef. To use the referenced service list, inject the savingsListRef bean reference into one of your client classes, as shown.

By default, the savingsAccountList bean property is a list of service objects (for example, java.util.List<SavingsAccount>). You could define the client class as follows:

package org.fusesource.example.client;

import org.fusesource.example.SavingsAccount;

public class Client {
    java.util.List<SavingsAccount> accountList;
    
    // Bean properties
    public java.util.List<SavingsAccount> getSavingsAccountList() {
        return accountList;
    }

    public void setSavingsAccountList(
                    java.util.List<SavingsAccount> accountList
    ) {
        this.accountList = accountList;
    }
    ...
}

To match both the interface and the component name (bean ID) of a stateless service, specify both the interface attribute and the component-name attribute on the reference element, as follows:

<reference id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           component-name="savings"/>

To match both the interface and the component name (bean ID) of a stateful service, specify both the interface attribute and the component-name attribute on the reference-list element, as follows:

<reference-list id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           component-name="savings"/>

You can select services by matching service properties against a filter. The filter is specified using the filter attribute on the reference element or on the reference-list element. The value of the filter attribute must be an LDAP filter expression. For example, to define a filter that matches when the bank.name service property equals HighStreetBank, you could use the following LDAP filter expression:

(bank.name=HighStreetBank)

To match two service property values, you can use & conjunction, which combines expressions with a logical and.For example, to require that the foo property is equal to FooValue and the bar property is equal to BarValue, you could use the following LDAP filter expression:

(&(foo=FooValue)(bar=BarValue))

For the complete syntax of LDAP filter expressions, see section 3.2.7 of the OSGi Core Specification.

Filters can also be combined with the interface and component-name settings, in which case all of the specified conditions are required to match.

For example, to match a stateless service of SavingsAccount type, with a bank.name service property equal to HighStreetBank, you could define a reference element as follows:

<reference id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           filter="(bank.name=HighStreetBank)"/>

To match a stateful service of SavingsAccount type, with a bank.name service property equal to HighStreetBank, you could define a reference-list element as follows:

<reference-list id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           filter="(bank.name=HighStreetBank)"/>

By default, a reference to an OSGi service is assumed to be mandatory (see Mandatory dependencies). It is possible, however, to customize the dependency behavior of a reference element or a reference-list element by setting the availability attribute on the element. There are two possible values of the availability attribute: mandatory (the default), means that the dependency must be resolved during a normal blueprint container initialization; and optional, means that the dependency need not be resolved during initialization.

The following example of a reference element shows how to declare explicitly that the reference is a mandatory dependency:

<reference id="savingsRef"
           interface="org.fusesource.example.SavingsAccount"
           availability="mandatory"/>

To cope with the dynamic nature of the OSGi environment—for example, if you have declared some of your service references to have optional availability—it is often useful to track when a backing service gets bound to the registry and when it gets unbound from the registry. To receive notifications of service binding and unbinding events, you can define a reference-listener element as the child of either the reference element or the reference-list element.

For example, the following blueprint configuration shows how to define a reference listener as a child of the reference manager with the ID, savingsRef:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
  
  <reference id="savingsRef"
             interface="org.fusesource.example.SavingsAccount"
             >
    <reference-listener bind-method="onBind" unbind-method="onUnbind">
      <bean class="org.fusesource.example.client.Listener"/>
    </reference-listener>
  </reference>

  <bean id="client" class="org.fusesource.example.client.Client">
    <property name="savingsAcc" ref="savingsRef"/>
  </bean>

</blueprint>

The preceding configuration registers an instance of org.fusesource.example.client.Listener type as a callback that listens for bind and unbind events. Events are generated whenever the savingsRef reference manager's backing service binds or unbinds.

The following example shows a sample implementation of the Listener class:

package org.fusesource.example.client;

import org.osgi.framework.ServiceReference;

public class Listener {
    
    public void onBind(ServiceReference ref) {
        System.out.println("Bound service: " + ref);
    }
    
    public void onUnbind(ServiceReference ref) {
        System.out.println("Unbound service: " + ref);
    }
    
}

The method names, onBind and onUnbind, are specified by the bind-method and unbind-method attributes respectively. Both of these callback methods take an org.osgi.framework.ServiceReference argument.