2011年11月13日

OSGI入門 その2 〜Serviceについて〜


前回は導入として、Hello Worldをやりましたが、今回からはOSGIの肝であるサービスの話をしていきます。
前述の通り、OSGIはバンドルと呼ばれるプログラムコンポーネントの集合体を動かすためのフレームワークです。
Serviceとはそのひとつのバンドルが公開する一連の処理を意味します。Javaオブジェクトであればなんでも
サービスになりえます。しかし、実際にはまず公開するIFを作成して、サービスとして登録するのはそのIFの
実装クラスになるでしょう。

・サービスバンドルの作成
まずはサービスバンドルを作ります。前回と同様、プラグインプロジェクトにて以下のプロジェクトを作成します。

プロジェクト名:ServiceBundle
Activator:test.service1.activator.Activator

続いてIFの作成

package test.service1.serviceif;

/**
 * サービスinterface
 * @author rag-timer
 *
 */
public interface MyServiceIF {
	/**
	 * なんらかのサービス
	 */
	public void print();
}

お次に実装の作成

package test.service1.serviceimpl;

import test.service1.serviceif.MyServiceIF;

public class MyServiceImpl implements MyServiceIF {
	@Override
	public void print() {
		System.out.println("This is my service!");
	}
}

なんの意味もないサービスですが、とりあえずこれで登録するネタはそろいました。では、Activatorで登録します。
サービスの登録にはBundleContext#registerService()を使用します。

/*
 * (non-Javadoc)
 * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
 */
public void start(BundleContext bundleContext) throws Exception {
	Activator.context = bundleContext;

	System.out.println("ServiceBundle start");

	//サービスの実体
	MyServiceIF service = new MyServiceImpl();

	//サービスの登録を行う
	context.registerService(MyServiceIF.class.getName(), service, null);

	System.out.println("Service registed");
}

registerService()の一つ目の引数はサービスのこのOSGIフレームワーク内で識別するための文字列です。
別に文字列であればなんでもかまいませんが、普通IFの名前を使用します。二つ目の引き数にはサービス
の実体を指定します。三つ目はこのサービスのプロパティを指定しますが今回は使いません。

続いて、このサービスを「公開する」ための作業を行います。バンドル間でのサービス呼び出しは一般の
Javaオブジェクトの呼び出しと大して変わりませんが、別バンドルが公開しているIFをそのままimportする
ことはできません。かならず「サービス公開者がexportし」「サービス消費者がimportする」という作業が
必要になります。この設定を行うのがMETA-INF/MANIFEST.MFです。なお公開はパッケージ単位で行います。

ではサービスの公開を行いましょう。MANIFEST.MFをダブルクリックし、[ランタイム」タブを選択して下さい。
左側の[エクスポートされるパッケージ]欄で追加を押下し、IFのパッケージを指定します。

1.png
これでサービス側のバンドルの準備は完了しました。

・サービス消費バンドルを作成

次にクライアントとなるサービス消費バンドルを作成します。

プロジェクト名:ServiceConsumerBundle
Activator:test.serviceconsumer1.activator.Activator

さて、まずはimportを行いましょう。これを行わないと、サービスIFが参照できません。
MANIFEST.MFをダブルクリックして、[依存関係]タブから[インポート済みパッケージ]を選んでサービスIFの
パッケージを選択します。なお、当然、exportをこの段階で行っていなければリストに出てきません。

2.png
続いて以下のようにActivatorを実装します。

package test.serviceconsumer1.activator;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

import test.service1.serviceif.MyServiceIF;

public class Activator implements BundleActivator {

	private static BundleContext context;

	private boolean flg = true;

	private final Thread myThread = new Thread(){
		public void run(){

			while(flg){

				//ServeiceReferenceの取得
				ServiceReference ref = Activator.context.getServiceReference(MyServiceIF.class.getName());

				//サービスの生成
				MyServiceIF service = (MyServiceIF)Activator.context.getService(ref);

				//サービスの呼び出し
				service.print();

				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					break;
				}

			}
		}
	};

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {

		System.out.println("ServiceConsumerBundle start");

		Activator.context = bundleContext;

		//スレッドのスタート
		myThread.start();
	}

	public void stop(BundleContext bundleContext) throws Exception {

		System.out.println("ServiceConsumerBundle stop");

		flg = false;
		Activator.context = null;
	}

}


Activator#startでは、定期的にサービスを使用するスレッドを起動してます。そのスレッドのrun()の中で
BundleContext#getServiceReference()でServiceReferenceオブジェクトを作成します。引数で渡すのは
先ほどサービスの登録に使用したサービス識別用の文字列、すなわちサービスのクラス名です。
作成したServiceReferenceを引数に、BundleContext#getService()でサービスが取得できます。
とりあえずはさらっと流します。

これで実行構成からこの2つのバンドルを構成し、実行すると・・・

osgi> ServicConsumerBundle start
ServiceBundle start
Service registed
This is my service!
This is my service!
・・・

てな感じで表示されるはずです。ちゃんとサービス呼べてますね。

・でもサービスをupdateすると・・・

では前回のようにサービスを書き換えてみましょう。適当にprintlnの文字列を変更して保存し、ssで
IDを確認後

update サービスバンドルのid

を実行します。すると・・・

osgi> Exception in thread "Thread-2" java.lang.NullPointerException: A null service reference is not allowed.
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.getService(BundleContextImpl.java:660)
at test.serviceconsumer1.activator.Activator$1.run(Activator.java:22)

こんなんなっちゃいました。update後、スレッド内の処理でServiceReferenceが取れていないようです。
この解決策は次回にします。

では。
posted by sandman at 00:07| Comment(0) | Java | このブログの読者になる | 更新情報をチェックする

2011年11月06日

OSGI入門 その1 〜Hello OSGI World〜


・OSGIとは何なのか?
OSGIとはOpen Services Gateway initiativeの略であり、もともとはサービスゲートウェイの仕様を
策定する目的で作られたものでした。サービスゲートウェイとして想定されるのはホームサービス
ゲートウェイによるネットワーク家電の制御プラットフォームなどが挙げられますが、実際はそれ以外
にも広く応用されている技術です。Javaプログラムを組む人ならば、まず間違いなくEclipseを使用した
経験があるでしょうが、このEclipse IDEもOSGIプラットフォームを採用しています。

OSGIはJavaベースのプラットフォームであり、その主な特徴として、JavaVMを上げ下げすることなしに
「bundle」と呼ばれるプログラムコンポーネントを起動/停止/インストール/アンインストールすること
ができます。Eclise IDEで言うところのbundle(バンドル)とはpluginのことでです。我々はEclipseの
「新規ソフトウェアのインストール」からネットワークを通じて自由にpluginをインストールできますが
それを可能にしているのがこのOSGIということになります。

・まずはバンドルを作ってみよう!
と、まあ堅苦しい話はこれくらいにして、実際に手を動かしてみましょー。
まずは恒例のHello Worldから。あ、すでにEclipseは入っている前提で話します。持ってないひとはインスコしてね。
私はEclipse3.6使ってます。

Eclipseにはバンドルを作成するための仕組みが標準で存在します。それが「プラグイン・プロジェクト」です。
パッケージエクスプローラから[新規]-[その他]-[プラグイン・プロジェクト]でプロジェクトを作成します。
プロジェクト名:HelloOSGIBundle
実行ターゲット:Equinox
で、次へをクリック、Activatorを生成のところで、パッケージ名やクラス名を好きに設定する。(別にdefaultで
もいいですけど)

これでとりあえず空のバンドルが作成できました。プロジェクトの中を見ていくと、まず先ほど作成した
Activatorがあるはずです。このActivatorはバンドルが起動/停止された際に実行する処理を記述するクラスです。
すなわち
Activator#stop()
Activator#start()
ですね。

ではまず、ここにそれぞれこんな感じで実装しましょう。



	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;

		System.out.println("Hello OSGI World!!!");
	}


	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;

		System.out.println("Good Bye OSGI World!!!");
	}


これで準備完了ですが、ひとつ重要なことがあります、プロジェクトの中にMETA-INF/MANIFEST.MFというファイル
がありますね?このファイルはこのバンドル自体の情報やバンドル間の依存関係など様々なことを規定するものです。
今後非常に重要になってくるファイルです。ダブルクリックすると、そのファイルの内容だけでなく、ファイルに設定
するためのGUIも用意されていることに気づくはずです。便利ですね。ただ、いまはまだ使いません。

・さっそく実行!
実行は[実行]-[実行構成]から[OSGI フレームワーク]で右クリックし、[新規構成]を選択します。
すると、なんだかごちゃごちゃとした画面が出てきますが、まず[バンドル]欄に注目してください。以下の二つのグループが
あると思います。
・ワークスペース・・・あなたのEclipseワークスペース内のバンドル群です。今回はHelloOSGIBundleですね。
・ターゲット・プラットフォーム・・・OSGIフレームワークである「Equinox」が提供するバンドル群です。
今回は作成したHelloOSGIBundleとosgi本体であるorg.eclipse.osgiしか要りませんので以下のように構成します。
ちなみに、右側にある必須バンドルの追加ボタンやOnly show selectedを使うと便利ですよ。

1.png

したらば、実行ボタンをおします。
以下のように表示されたでしょうか?

osgi> Hello OSGI World!!!

これでまずは実行できました。でもこれじゃpublic static void main(String args[])でHello Worldしたのと変わりま
せんね。なのでosgiっぽいことしてみましょう。

・状態表示してみる
結果が表示されているコンソールにカーソルをあわせ、Enterキーを押してみてください。すると
osgi>
という文字列が現れると思います。その状態で「ss」と入力し、Enterキーを押してください。
こんなんが現れたと思います。

Framework is launched.

id State Bundle
0 ACTIVE org.eclipse.osgi_3.6.2.R36x_v20110210
1 ACTIVE HelloOSGIBundle_1.0.0.qualifier


すでにお気づきでしょうが、この「ss」は現在のOSGIプラットフォームにインストールされているバンドルの一覧表示
コマンドです。このコマンド自体はOSGIフレームワークによって異なります。equinoxではssですね。

idというのはこのOSGIフレームワーク上で1つのバンドルに一意でふられるIDです。操作もこのIDを通じて行います。
Stateはバンドルの状態を意味します。Activeは稼動中ってことですね。

・バンドルを停止してみる
んじゃ、バンドルを止めてみましょう。以下のコマンドを打ってください。

osgi>>stop 1


すると、こんな感じで表示されるはずです。

Good Bye OSGI World!!!


先ほど実装したActivator#stop()が呼ばれたわけですね。ただしあくまでも、バンドルが停止しただけですので、
JavaVMは落ちていません。つまりこれがOSGIの特徴なわけです。

・バンドルを更新してみる
では、こんどはバンドル実装を修正して、更新をかけてみましょう。さきほどのSystem.out.printlnに
適当な文字列を追加します。修正が完了して、コンパイルが通ったら以下を入力。
osgi> update 1


んで、そのままstartコマンドを打つと・・・

osgi> start 1
update - Hello OSGI World!!!


「update - 」の文字列が追加されてますね!!しつこいですがJAVAVMはあがりっぱなしです。
※今回は停止している前提で書きますが、もし、updateをかけたバンドルが起動していた場合、
updateの際、自動的に停止/起動されます。

次回からはしばらく、OSGIの肝であるサービスのお話になります。
ではまた。
posted by sandman at 18:07| Comment(0) | Java | このブログの読者になる | 更新情報をチェックする

2011年09月20日

手羽元のトマトワイン煮込み


[材料(3人分)]
鳥の手羽元 9本
にんにく 1かけ
たまねぎ 1個
ホールトマト1缶
ブロッコリー 1房
塩コショウ 適量
オリーブオイル 適量
コンソメ 適量


[作り方]
@鍋にオリーブオイルを引いてみじん切りにしたにんにくを弱火で炒める。
A香りがたったらみじん切りにした玉ねぎを加え、5〜6分炒める
B塩コショウした手羽元を加え表面に赤いところがなくなるまで炒める
Cホールトマトをボウルに移し、トマトを握りつぶしてから軽く塩コショウを振り、鍋に入れる。
Dひと煮たちしたら、一口大に切ったブロッコリーを投入。
E続いてコンソメと赤ワインを投入。量は適当。
E弱火で20分ほどコトコト煮る。

手羽元がぷりぷりで本当にうまい。ワインは安物でいいから入れたほうがいい。
味が格段に変わる。ブロッコリーは別で煮てから最後に加えたほうが彩りはいいかも。
メンドクサイけども。手羽元じゃなくて、鳥の腿肉でも普通にうまい。

201109092101000.jpg
posted by sandman at 22:53| Comment(0) | 料理 | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

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