Menu Close

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

概要

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

サービス参照の管理

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

参照マネージャー

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

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

deploy simple svc 01

クライアントの Blueprint コンテナーの Bean は、OSGi サービスレジストリーからサービスオブジェクト (バッキングサービス) によってバッキングされるプロキシーオブジェクト (提供済みオブジェクト) にインジェクトされます。このモデルは、以下の方法で、ステートレスサービスが相互変更可能であるという事実を明示的に利用します。

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

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

参照リストマネージャー

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

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

deploy simple svc 02

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

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

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

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

たとえば、ステートレスの SavingsAccount サービスを参照するには( 例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>

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

クライアントクラスにインジェクトされた bean プロパティーは、Savings Account から割り当て可能なタイプにすることができます。たとえば、以下のように 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 サービスを参照するには( 例12.1「単一のインターフェースを使用したサンプルサービスのエクスポート」を参照)、以下のように reference-list 要素を定義します。

<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)の両方に一致するには、以下のように reference 要素の interface 属性と component-name 属性の両方を指定します。

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

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

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

サービスプロパティーとフィルターの一致

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

(bank.name=HighStreetBank)

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

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

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

フィルターは、インターフェースと コンポーネント名の設定と組み合わせることもできます。この場合は、 指定した条件をすべて一致させる必要があります。

たとえば、Savings Account タイプの ステートレス サービスに一致し、HighStreetBank と同等の bank .name サービスプロパティーを使用する場合は、以下のように 参照 要素を定義します。

<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 属性を設定して、参照 要素または参照 リスト 要素の依存関係の動作をカスタマイズできます。

availability 属性の値は 2 つあります。

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

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

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

参照リスナーの指定

OSGi 環境の動的な性質に対応するため、オプションの availability-it に宣言したサービス参照の一部が、バッキングサービスがレジストリーにバインドされている場合、またレジストリーからバインドされないタイミングを追跡する場合に便利です。サービスバインディングおよびバインド解除イベントの通知を受け取るには、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>

上記の設定では、バインドおよびバインド解除 イベントをリッスンするコールバックとして 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);
    }

}

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