OSGiフレームワーク Apache Felix その1

OSGiとは

OSGi(Open Services Gateway initiative)とは、Java のモジュールを管理する実行基盤です。元々はシステムの再起動が難しい組み込みシステムにおいて、再起動なくモジュールの入れ替えなどをネットワーク経由にて行うためのものでしたが、最近では、Eclipse や Spring、JBoss の実行基盤としても採用されています。仕様は OSGi Alliance により策定されています。
http://www.osgi.org/Main/HomePage

OSGiでは何ができるのか

OSGiでは、Java のモジュールをバンドルと呼びます。このバンドルをOSGi実行環境にて管理することで以下のようなことが実現できます。

  • バンドルの動的なインストール
  • バンドルの依存関係の解決
  • バンドルのバージョン管理
  • バンドルによるアクセス制御

バンドルとは

バンドルの実態は、JARファイルです。JARファイル中のマニフェストOSGiの属性情報を付与し、この属性情報を元にバンドルの管理が行われます。

OSGiの実装

OSGiはオープンな仕様であり、その実装はさまざまなものがあります。以下が有名どころです。

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


次回はサービスの登録を行います。