2011年11月13日

OSGI入門 その3 〜Serviceの動的アップデート〜


さて、前回はupdateが上手くいかないところでしたね。まずはOSGIの仕様はBundleのupdateについて
どのように規定しているのでしょうか。仕様を見てみます。
※ちなみに、仕様のドキュメントはここからダウンロードできます。

The update process supports migration from one version of a bundle to a newer version of the same
bundle. The exports of an updated bundle must be immediately available to the Framework. If none
of the old exports are used, then the old exports must be removed. Otherwise, all old exports must
remain available for existing bundles and future resolves until the bundle is refreshed, see Refreshing
on page 148, or the Framework is restarted.

(訳)
updateプロセスはある同一バンドルに関して、古いバージョンから新しいバージョンへの移行をサポート
します。updateされるバンドルがexportしているサービスは直ちにフレームワーク内で有効化されなければなりません。
もし、古いexportがすべて使われなくなったなら、それは取り除かれなければなりません。それ以外の場合、すべての古い
exportはそのバンドルがrefreshされるか、フレームワークが再起動されるまで、既存バンドルおよび以降にインストール
されるバンドルから使用可能な状態に残しておかなければなりません。

なるほど、つまり変更を完全に有効にするにはOSGIフレームワークを再起動するか、「refresh」をかけろ
ということですね。もちろん、フレームワークの再起動をせずにやりたいので、refreshコマンドを使ってみましょう。

・refreshコマンドを使おう!

前回のプログラムをそのまま使います。適当な文字列でMyServiceImpleを修正してからrefreshをかけます。
すると・・・

osgi>refresh 2

osgi> ServiceConsumerBundle stop
ServiceBundle stop
ServiceBundle start
Service registed
ServiceConsumerBundle start
This is my service! version 2!
This is my service! version 2!
This is my service! version 2!

でけました。でもその前に標準出力をよく見てみると、ConsumerBundleも再起動されていることに気づきます。
つまり・・・

refresh→ConsumerBundle停止→ServiceBundle再起動→ConsumerBundle起動

となるわけです。要するに、refreshコマンドを打つと、対象バンドルがexportしているパッケージに依存しているバンドル
を停止し、対象バンドルを再起動してから、依存バンドルを起動するということのようですね。

うーん。なんか嫌ですね。できることなら、updateしたバンドルだけ再起動して終わりたいものです。
上記の仕様を見るかぎりだと駄目そうなんですが、実はこれやり方があります。といっても大したことではなく
バンドルの構成を変更するだけです。どうするかというと「IFと実装を別バンドルにする」これだけです。

・IFと実装を別バンドルに!

ではさっそくやってみましょう。といってもただIFと実装を分けるだけです。以下のバンドルを作成します。

■IFだけのバンドル
ServiceIFBundle

■実装バンドル
ServiceBundle2

■消費バンドル
ServieConsumer2

中身は前回と全く一緒。ただIFをMyServiceIFに移しただけです。もちろんIFがServiceIFBundleに移ったので
exportしているのはServiceIFBundleで残りの二つはそれをimportすることになります。

この3バンドルを構成して実行しましょう。

osgi> ServiceBundle start
Service registed
ServiceConsumerBundle start
This is my service!
This is my service!

ここまでは一緒ですね。ではMyServiceImplを適当に修正して、updateしてみましょう。

osgi> update 3
ServiceBundle stop
ServiceBundle start
Service registed
This is my service! update version
This is my service! update version
This is my service! update version

おお!ちゃんと新しいの取れてますね。素晴らしいです。

・IFバンドルと実装を別にすることについての補足

私が見る限り、OSGIの仕様として「IFと実装のバンドルはわけなさい」と規定しているわけではなさそうです。
ただ、ネットを調べてみると、この話題は議論されています。

Different osgi bundles with implementations of the same interface - where to place that inferface?

ここでの回答もやはり「分けた方がいい」とあります。理由は実装を後で置き換えられるということと、それから
対象バンドルを消費バンドルの再起動なしにhot replaceできるという理由が挙げられています。後者はまさに
今われわれが実験したことですね。

やはり、イディオムとしてはIFバンドルと実装バンドル分けておいたほうがいいんだと思われます。また、他の
利点としてはA実装バンドル⇔B実装バンドルというようにお互いのサービスを呼び合うような場合、IFと実装が
同居していると相互参照でエラーになっちゃいます。分けておけば、たすきがけのように呼び合えますね。

さて、次はServiceTrackerあたりをやろうかと思います。たぶん。

では。
posted by sandman at 16:07| Comment(0) | Java | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。