LibraryToggle FramesPrintFeedback

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 16.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.

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 16.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 16.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;
    }
    ...
}

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.

Comments powered by Disqus
loading table of contents...