OSGiとは
OSGi(Open Services Gateway initiative)とは、Java のモジュールを管理する実行基盤です。元々はシステムの再起動が難しい組み込みシステムにおいて、再起動なくモジュールの入れ替えなどをネットワーク経由にて行うためのものでしたが、最近では、Eclipse や Spring、JBoss の実行基盤としても採用されています。仕様は OSGi Alliance により策定されています。
http://www.osgi.org/Main/HomePage
OSGiでは何ができるのか
OSGiでは、Java のモジュールをバンドルと呼びます。このバンドルをOSGi実行環境にて管理することで以下のようなことが実現できます。
- バンドルの動的なインストール
- バンドルの依存関係の解決
- バンドルのバージョン管理
- バンドルによるアクセス制御
OSGiの実装
OSGiはオープンな仕様であり、その実装はさまざまなものがあります。以下が有名どころです。
- Equinox http://www.eclipse.org/equinox/
- Apache Felix http://felix.apache.org/site/index.html
- Knopflerfish http://www.knopflerfish.org/
Apache Felix
Apache Felix にてOSGiがどのようなものか見ていきます。ここでは、Felix Framework Distribution 2.0.0 を使います。ダウンロードページから以下のファイルを取得して解凍します。
- felix-framework-2.0.0.zip
解凍後のディレクトリ構成は以下のようになります。
felix-framework-2.0.0 ├─bin │ └ felix.jar ├─bundle │ ├ org.apache.felix.bundlerepository-1.4.1.jar │ ├ org.apache.felix.shell-1.4.0.jar │ └ org.apache.felix.shell.tui-1.4.0.jar ├─conf │ └ config.properties └─doc └ 各種ドキュメント
felix.jar がOSGi実装の本体で、bundleディレクトリにいくつかのバンドルが格納されています。
Felixの起動
解凍したディレクトリにてFelixを実行すると、対話型のシェルが立ち上がります。
felix-framework-2.0.0> java -jar bin/felix.jar Welcome to Felix ================ ->
この時点でディレクトリ構成を確認してみると、以下のようにfelix-cacheディレクトリが増えています。
felix-framework-2.0.0 ├─bin ├─bundle ├─conf ├─doc └─felix-cache ├─bundle0 ├─bundle1 ├─bundle2 └─bundle3
Felix はデフォルトで、bundle ディレクトリにあるバンドルをインストールします。このときバンドルは felix-cache にキャッシュとしてコピーされます。
バンドルの状態確認
psコマンドで、バンドルの状態を確認できます。
-> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [ 1] Apache Felix Bundle Repository (1.4.1) [ 2] [Active ] [ 1] Apache Felix Shell Service (1.4.0) [ 3] [Active ] [ 1] Apache Felix Shell TUI (1.4.0)
それぞれのバンドルは ID で管理されており、Active な状態となっていることが分かります。ID が 0 のバンドルは Felix 本体となります。その他のバンドルが、bundle ディレクトリからインストールされたものとなります。そのため、ID 0 のバンドルを停止すると Felix が終了します。
バンドルの作成
バンドルを作成するには、BundleActivator を実装したクラスを作成し、マニフェストを含めた JAR ファイルを作成します。ここでは felix を解凍したディレクトリ中に work ディレクトリを作成し、この中でバンドルを作成していきます。以下のような構成となります。
felix-framework-2.0.0 └ work └ example1 ├ MANIFEST.MF └ tutorial └ example1 └ Activator.java
バンドルに含むクラス Activator.java を作成します。
package tutorial.example1; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceEvent; public class Activator implements BundleActivator, ServiceListener { public void start(BundleContext context) { System.out.println("Starting to listen for service events."); context.addServiceListener(this); } public void stop(BundleContext context) { context.removeServiceListener(this); System.out.println("Stopped listening for service events."); } public void serviceChanged(ServiceEvent event) { String[] objectClass = (String[]) event.getServiceReference().getProperty("objectClass"); if (event.getType() == ServiceEvent.REGISTERED) { System.out.println("Ex1: Service of type " + objectClass[0] + " registered."); } else if (event.getType() == ServiceEvent.UNREGISTERING) { System.out.println("Ex1: Service of type " + objectClass[0] + " unregistered."); } else if (event.getType() == ServiceEvent.MODIFIED) { System.out.println("Ex1: Service of type " + objectClass[0] + " modified."); } } }
ここで実装している BundleActivator インターフェースには start() と stop() のメソッドがあり、バンドルの起動時と停止時にコンテナから呼び出されます。
ServiceListener インターフェースには serviceChanged() メソッドがあり、サービスのライフサイクルの変更時にコンテナから呼び出されます。
MANIFEST.MF の作成
バンドルに属性情報を付与する MANIFEST.MF を作成します。
Bundle-Name: Service listener example Bundle-Description: A bundle that displays messages at startup and when service events occur Bundle-Vendor: Apache Felix Bundle-Version: 1.0.0 Bundle-Activator: tutorial.example1.Activator Import-Package: org.osgi.framework
項目の説明は以下となります。
項目名 | 説明 |
---|---|
Bundle-Name | バンドルの名前 |
Bundle-Description | バンドルの説明 |
Bundle-Vendor | バンドルの提供ベンダ |
Bundle-Version | バンドルのバージョン |
Bundle-Activator | バンドルの起動に使用するorg.osgi.framework.BundleActivatorを実装したクラス |
Import-Package | 使用するほかのバンドルの公開パッケージ |
Export-Package | ほかのバンドルへ公開するパッケージ |
JARの作成
作成したクラスと MANIFEST.MF からバンドルを作成します。クラスをコンパイルしてJARに固めます。
> cd work\example1 > javac -classpath ..\..\bin\felix.jar tutorial\example1\*.java > jar cfm example1.jar manifest.mf tutorial\example1
作成したバンドルのインストール
作成した example1.jar を Felix にインストールします。インストールには install コマンドを使用します。
-> install file:work\example1\example1.jar Bundle ID: 4 -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [ 1] Apache Felix Bundle Repository (1.4.1) [ 2] [Active ] [ 1] Apache Felix Shell Service (1.4.0) [ 3] [Active ] [ 1] Apache Felix Shell TUI (1.4.0) [ 4] [Installed ] [ 1] Service listener example (1.0.0)
バンドルID 4 としてインストールされたことが分かります。サービスをスタートさせてみます。
-> start 4 Starting to listen for service events. -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [ 1] Apache Felix Bundle Repository (1.4.1) [ 2] [Active ] [ 1] Apache Felix Shell Service (1.4.0) [ 3] [Active ] [ 1] Apache Felix Shell TUI (1.4.0) [ 4] [Active ] [ 1] Service listener example (1.0.0)
start コマンド発行後に「Starting to listen for service events.」と、作成したクラスのstart()メソッドによりメッセージが表示されていることが確認できます。またバンドルが Active となっていることも確認できます。
バンドルの停止
バンドルの停止には stop コマンドを使用します。
-> stop 4 Stopped listening for service events. -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [ 1] Apache Felix Bundle Repository (1.4.1) [ 2] [Active ] [ 1] Apache Felix Shell Service (1.4.0) [ 3] [Active ] [ 1] Apache Felix Shell TUI (1.4.0) [ 4] [Resolved ] [ 1] Service listener example (1.0.0)
stopメソッドのメッセージが出力されていることが確認できます。
バンドルを uninstall します。
-> uninstall 4 -> ps START LEVEL 1 ID State Level Name [ 0] [Active ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [ 1] Apache Felix Bundle Repository (1.4.1) [ 2] [Active ] [ 1] Apache Felix Shell Service (1.4.0) [ 3] [Active ] [ 1] Apache Felix Shell TUI (1.4.0)
Felixの停止
shutdownにより対話型シェルが終了します。
-> shutdown
次回はサービスの登録を行います。