12.3. サービスのインポート

概要

このセクションでは、OSGi サービスレジストリーにエクスポートされた OSGi サービスへの参照を取得して使用する方法について説明します。reference 要素または reference-list 要素のいずれかを使用して、OSGi サービスをインポートできます。reference 要素はステートレスサービスへのアクセスに適していますが、reference-list 要素はステートフルサービスへのアクセスに適しています。

サービス参照の管理

OSGi サービス参照を取得するための以下のモデルがサポートされています。

参照マネージャー

参照マネージャーインスタンスは、Blueprint reference 要素によって作成されます。この要素は単一のサービス参照を返すので、ステートレス サービスへのアクセスに推奨のアプローチです。図12.1「ステートレスサービスへの参照」 は、参照マネージャーを使用してステートレスサービスにアクセスするためのモデルの概要を示しています。

図12.1 ステートレスサービスへの参照

deploy simple svc 01

クライアント Blueprint コンテナー内の Bean には、OSGi サービスレジストリーからのサービスオブジェクト (バッキングサービス) によってサポートされるプロキシーオブジェクト (提供されたオブジェクト) が注入されます。このモデルは、次のように、ステートレスサービスが交換可能であるという事実を明示的に利用しています。

  • reference 要素の基準と一致する複数のサービスインスタンスが見つかった場合は、参照マネージャーは、バッキングインスタンスのいずれかを任意に選択することができます (交換可能であるため) 。
  • バッキングサービスがなくなった場合には、参照マネージャーは、同じタイプの他の利用可能なサービスの 1 つを使用するようにすぐに切り替えることができます。したがって、次のメソッド呼び出しまでの間、プロキシーが同じバッキングサービスに接続されたままであるという保証はありません。

そのため、クライアントとバッキングサービス間のコントラクトは ステートレス であり、クライアントは常に同じサービスインスタンスと通信しているとは限りません。一致するサービスインスタンスがない場合は、ServiceUnavailable 例外を出力する前にプロキシーは一定時間待機します。タイムアウトの長さは、timeout 要素に reference 属性を設定することで設定できます。

参照リストマネージャー

参照リストマネージャーインスタンスは、Blueprint reference-list 要素によって作成されます。この要素はサービス参照のリストを返し、ステートフル サービスへのアクセスに推奨のアプローチです。図12.2「ステートフルサービスへの参照のリスト」 は、参照リストマネージャーを使用してステートフルサービスにアクセスするためのモデルの概要を示しています。

図12.2 ステートフルサービスへの参照のリスト

deploy simple svc 02

クライアントの Blueprint コンテナーの Bean は、プロキシーオブジェクトの一覧が含まれる java.util.List オブジェクト (提供済みオブジェクト) で注入されます。各プロキシーは、OSGi サービスレジストリー内の一意のサービスインスタンスによってサポートされています。ステートレスモデルとは異なり、ここではバッキングサービスは互換性があるとは見なされません。実際、リスト内の各プロキシーのライフサイクルは、対応するバッキングサービスのライフサイクルと密接に関連しています。サービスが OSGi レジストリーに登録されると、対応するプロキシーが同時に作成され、プロキシーリストに追加されます。また、サービスが OSGi レジストリーから登録解除されると、対応するプロキシーがプロキシーリストから同時に削除されます。

したがって、プロキシーとそのバッキングサービス間のコントラクトは ステートフル であり、クライアントは、特定のプロキシーでメソッドを呼び出すときに、常に 同じ バッキングサービスと通信していると想定されます。ただし、バッキングサービスが利用できなくなる可能性があり、その場合、プロキシーは古くなります。古いプロキシーでメソッドを呼び出すと、ServiceUnavailable 例外が生成されます。

インターフェイスによるマッチング (ステートレス)

ステートレスサービス参照を取得する最も簡単な方法は、reference 要素の interface 属性を仕様して一致するインターフェイスを指定することです。interface 属性の値がサービスのスーパータイプである場合や、属性値がサービスによって実装された Java インターフェイスである場合、サービスは一致すると見なされます (interface 属性は Java クラスまたは Java インターフェイスのいずれかを指定できます)。

たとえば、ステートレス SavingsAccount サービスを参照するには、以下のように reference 要素を定義します (例12.1「単一のインターフェイスを使用したサンプルサービスのエクスポート」 を参照)。

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

reference 要素によって ID savingsRef を持つ参照マネージャー Bean が作成されます。参照されたサービスを使用するには、以下に示すように savingsRef Bean をクライアントクラスのいずれかに注入します。

クライアントクラスにインジェクトされた bean プロパティーは、SavingsAccount から割り当て可能なあらゆるタイプにすることができます。たとえば、以下のように Client クラスを定義できます。

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

インターフェイスによるマッチング (ステートフル)

ステートフルサービス参照を取得する最も簡単な方法は、reference-list 要素の interface 属性を仕様して一致するインターフェイスを指定することです。その後、参照リストマネージャーはすべてのサービスのリストを取得します。interface 属性の値はサービスのスーパータイプか、またはサービスによって実装されてた Java インターフェイスのいずれかです (interface 属性は Java クラスまたは Java インターフェイスのいずれかを指定できます)。

たとえば、ステートフル SavingsAccount サービスを参照するには、以下のように reference-list 要素を定義します (例12.1「単一のインターフェイスを使用したサンプルサービスのエクスポート」 を参照)。

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

reference-list 要素によって ID savingsListRef を持つ参照リストマネージャー Bean が作成されます。参照されたサービスリストを使用するには、以下に示すように savingsListRef Bean 参照をクライアントクラスのいずれかに注入します。

デフォルトでは、savingsAccountList Bean プロパティーはサービスオブジェクトのリストです (たとえば、java.util.List<SavingsAccount>)。クライアントクラスは次のように定義できます。

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

インターフェイスとコンポーネント名によるマッチング

ステートレスサービスのインターフェイスとコンポーネント名 (Bean ID) の両方と一致するには、以下のように interface 属性と component-name 属性を reference 要素に指定します。

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

ステートフルサービスのインターフェイスとコンポーネント名 (Bean ID) の両方と一致するには、以下のように interface 属性と component-name 属性を reference-list 要素に指定します。

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

フィルターを使用したサービスプロパティーの照合

フィルターに対してサービスプロパティーを照合して、サービスを選択できます。フィルターは、reference 要素または reference-list 要素で filter 属性を使用して指定されます。filter 属性の値は LDAP フィルター式である必要があります。たとえば、bank.name サービスプロパティーが HighStreetBank の場合にマッチするフィルターを定義するには、以下の LDAP フィルター式を使用します。

(bank.name=HighStreetBank)

2 つのサービスプロパティーの値を一致させるには、論理 and で式を組み合わせる & 結合を使用できます。たとえば、foo プロパティーが FooValue と等しく、bar プロパティーが BarValue と等しいことを必要とするには、以下の LDAP フィルター式を使用できます。

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

LDAP フィルター式の完全な構文は、OSGi コア仕様 のセクション 3.2.7 を参照してください。

フィルターは、interface および component-name 設定と組み合わせることもできます。この設定では、指定したすべての条件が一致する必要があります。

たとえば、SavingsAccount タイプのステートレス サービスを HighStreetBank と等しい bank.name サービスプロパティーと一致させるには、以下のように reference 要素を定義します。

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

SavingsAccount タイプのステートフル サービスを HighStreetBank と等しい bank.name サービスプロパティーと一致させるには、以下のように reference-list 要素を定義します。

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

必須/任意の指定

デフォルトでは、OSGi サービスへの参照は必須であると見なされます (必須の依存関係 参照)。要素に availability 属性を設定して、reference 要素または reference-list 要素の依存関係動作をカスタマイズできます。

availability 属性には、可能な値が 2 つあります。

  • mandatory (デフォルト) は、通常の Blueprint コンテナーの初期化中に依存関係を解決する必要があることを意味します。
  • optional は、依存関係が初期化中に解決される必要がないことを意味します。

以下の reference 要素の例では、参照が必須の依存関係であることを明示的に宣言する方法を示しています。

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

参照リスナーの指定

たとえば、一部のサービス参照に optional が使用できることを宣言した場合など、OSGi 環境の動的な性質に対応するには、バッキングサービスがレジストリーにバインドされたときと、レジストリーからバインド解除されたときを追跡すると便利なことがよくあります。サービスバインディングおよびバインドイベントの通知を受信するには、reference-listener 要素を reference 要素または reference-list 要素の子として定義できます。

たとえば、以下の Blueprint 設定は、参照リスナーを、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>

前述の設定は、bindunbind イベントをリッスンし、そのコールバックとして org.fusesource.example.client.Listener タイプのインスタンスを登録します。イベントは、savingsRef 参照マネージャーのバッキングサービスがバインドまたはバインド解除されるたびに生成されます。

以下の例は、Listener クラスの実装例を示しています。

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);
    }

}

メソッド名 onBind および onUnbind は、それぞれ bind-method 属性および unbind-method 属性によって指定されます。これらのコールバックメソッドは両方とも org.osgi.framework.ServiceReference 引数を取ります。