2012-03-28 5 views
5

Eclipse RCPでアプリケーションを開発しています。私はサービスの設計に関する設計上の決定に助けが必要です。OSGiサービス・アーキテクチャー:消費者の要求に応じたサービスの作成

他のモジュールにREngineオブジェクトを提供するために使用されるバンドルがあります。 REngineは、計算エンジンへのインタフェースであり、複数の方法で実装できます。バンドルは、リモートサーバーに接続するか、ローカル計算スレッドを開始することによって、REngineのインスタンスを提供します。一部のバンドルでは、GUIによる設定が必要です(ヘッドレスプラットフォームでも使用できる必要があります)。クライアントバンドルは、並列計算のために複数のREngineオブジェクトを要求することがあります。

私は現在REngineサービスを提供するためにこれらのモジュールを登録しています。このサービスはServiceFactoryによって作成され、ServiceFactoryはローカル計算インスタンスまたはリモート(サーバー)インスタンスを起動します。クライアントは、REngineクラスのすべてのサービス登録を試して、適切なものを選択する責任があります。次のようにこれを行うには

コードをまとめることができます。

class API.REngine { ... } 

class REngineProvider.Activator { 
    public void start(BundleContext ctx) { 
     ctx.registerService(REngine.class.getName(), new REngineFactory(), null); 
    } 
} 
class REngineProvider.REngineFactory implements ServiceFactory { 
    public Object getService(Bundle bundle, ServiceReference reference) { 
     return new MyREngineImplementation(); 
    } 
    public void ungetService(REngine service) { 
     service.releaseAssociatedResources(); 
    } 
} 

class RConsumer.Class { 
    REngine getREngine() { 
     ServiceReference[] references = bundleContext.getAllServiceReferences(REngine.class.getName(), null); 
     for(ServiceReference ref: references) { 
      try { 
      return bundleContext.getService(ref); 
      } catch (Exception e) {} // too bad, try the next one 
     } 
    } 
} 

私はこのモデルを維持したいと思います。 OSGiサービス仕様は、REngineオブジェクトが、もはや必要なくなったときにリリースされるべき生きたオブジェクトであるという私のビジネス要件に合っているのはいいことです。

ただし、登録サービスでは、バンドルごとに1つのサービスインスタンスしか提供できません。 2回目にサービスが要求されると、キャッシュされたインスタンスが返されます(新しいインスタンスを作成するのではなく)。これは私の要求と一致しません。バンドルは同じプロバイダから複数のREngineオブジェクトを取得できる必要があります。

私は既に他のOSGiフレームワーククラスを見てきましたが、何も助けてくれないようです。代替はホワイトボードモデルですが、REngineProviderバンドルで使用されるREngineRequestServiceを登録して、実際のREngineを提供するのは変です。

OSGiでこれを実装するにはどうすればよいですか?ここでは、私の要件リストを示します。

  1. REngineProviderバンドルを簡単に有効にしたり無効にしたりできます。クライアントコードは代わりに別のプロバイダを使用します。
  2. REngineProviderバンドルの設定。
  3. クライアントバンドルごとに複数のREngineインスタンス。
  4. REngineインスタンスの明示的なリリース
  5. REngineの作成が失敗する可能性があります。クライアントモジュールはその理由を知ることができるはずです。

ちょうど私が将来の参考として選択したソリューションを追加します。 OSGi Servicesプラットフォームは「サービスを要求する」ためのものではないようです。サービスを作成するプロバイダバンドルと、サービスを検索して使用できるクライアントバンドルです。ユーザーの要求に応じて自動的に「ファクトリ」を提供することはできません。

選択される溶液は、OSGi whiteboard modelを含む。一見すると、これは管理が非常に難しいように見えるかもしれませんが、Blueprintは多くを助けることができます!

プロバイダ青写真。xmlファイル:

<reference-list interface="org.application.REngineRequest" 
      availability="optional"> 
    <reference-listener 
      bind-method="bind" unbind-method="unbind"> 
     <bean class="org.provider.REngineProvider"/>   
    </reference-listener> 

クラスREngineRequestは、入力に、プロバイダ彼REngineオブジェクト可能共有APIクラスである、または作成が機能しなかった理由を説明する例外を設定します。クライアントの場合

、REngineを使用すると、今やってするのと同じくらい簡単です:

REngineRequest req = new REngineRequest(); 
ServiceRegistration reg = bundleContext.registerService(req, REngineRequest.class.getName(), engineCreationProperties); 
req.getEngine().doSomeStuff(); 
reg.unregister(); 

私たちは、クライアントがREngineを使用している間に、プロバイダが停止することはありませんという仮定を作ります。そうであれば、REngineは無効になります。

答えて

3

ComponentFactoryDeclarative Servicesが必要です。ほとんどの場合、手動でサービスを登録して検索する代わりにDSを使用する必要があります。

プロバイダ側はREngineの工場出荷時のサービスを登録する必要があります(ファクトリ自体を実装する必要はありません.DSがこれを行います)。コンスマーは、1対多の依存関係をREngineサービスに宣言する必要があります。実行時に、すべての利用可能なファクトリが注入され、消費者は実際のREngineインスタンスを作成するためにそれらを通過できます。

+0

DSの代わりにBluePrintとPROTOTYPEアノテーションをお勧めしますか?私は違いを見て苦労している。 – parasietje

+0

私はBlueprintとプロトタイプの範囲を提案しようとしていました。 Blueprintは宣言型サービスよりも多くのノブを持っています。 –

+0

残念ながら、オブジェクトの作成時にコンテキスト(プロパティ)が必要です。単純なファクトリメソッドを指定することはできませんが、インスタンス化されるクラスを指定する必要があります。青写真のようなものがあることを願っています! – parasietje

1

解決策の1つは、REngine実装自体ではなくサービスとしてREngineFactoryを登録し、getServiceメソッドからファクトリを返すことです。こうすることで、クライアントはファクトリを検索し、正常に見つかったときにそのファクトリを使用して新しいREngineの実装を取得できます。

3

2年前、私はGenuine Service Factoriesを作成して、後でパラメータ化されたサービスとなるようにしました。しかし、分析後、何も必要ないことが判明しました。工場をサービスとして登録するだけです。

ただし、

私はあなたのサービスについて十分に分かっていませんが、クライアントバンドルから制御を取り除くことで大幅に簡素化できることは非常によく聞かれます。クライアントバンドルは、サービスレジストリで利用できるどんなREngineサービスREngineが必要な複数のバンドルがあり、同じREngineを共有してはならない場合(ほとんどの場合そうであるはずです)、その使用タイプを通知します。

このモデルが可能であれば、通常は大幅に簡略化されます。私は一般的にDSを使用してインスタンスを駆動する設定管理設定を使用します(DSの最も有用な機能の1つ、http://www.aqute.biz/Bnd/Componentsを参照)。メタタイプの統合により、ユーザー・インターフェースを使用して構成プロパティーを編集することもできます。

+0

これはおそらく最も簡単な実装です。サービスを取得しているバンドルは、新しいサービスの登録をトリガーします。 – parasietje

+0

ああ!そのため、解決策は、「Configuration Admin」を使用して「次のREngineインスタンスを作成してもらいたい」というリストを提供してからサービスを取得することです。おそらくREngineオブジェクトの代わりに例外を発行することによって、例外を伝えることができます。残っている問題は、サービスを要求してからサービスを受けるまでのタイミングの問題です。 – parasietje

+2

サービスを取得しても、新規登録は行われません。 2つの手順があります。クライアントバンドルはレジストリにあるものをすべて使用し、構成管理者はDSコンポーネントを通じて利用可能なものを定義します。 DSコンポーネントでは、依存関係を表現するため、タイミングに問題はありません。あなたがミドルウェア開発者でない限り、ServiceReferencesを使用しないでください... DSは非常にきれいです、特にアノテーション –