OGI入門:Declarative Serviceの消費者


http://230996.blog.chinajavaworld.com/entry/3719/0/
 
EclipseZone「OGi入門」シリーズ講座へようこそ.今日の授業に入る前に、すべての講座の前の部分を見つけてほしいです.私のブログにあります.前回私たちは初めてDeclarate Serviceに触れました.今回はDeclarate Serviceの消費者の方を見てみます.以前、私達はjava.lang.Runnableインターフェイスの下でサービスを登録しました.このサービスに依存するコンポーネントを作成します.議論されているように、Declarative Services仕様は、以前の授業で書かれたOSI「glue」コードではなく、あなたのコードに焦点を合わせるためのすべての応用ロジックです.このため、コードに潜り込むだけですが、プロジェクトを作成する必要があります.以下は最終コースで同じ手順ですが、プロジェクト名として「SimpleImporter」を使います.以下のコードをブラウザからコピーして、新しいEclipseプロジェクトのsrcフォルダに貼り付けます.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package org.example.ds;
 
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
 
public class SampleCommandProvider1 implements CommandProvider {
	
	private Runnable runnable;
	
	public synchronized void setRunnable(Runnable r) {
		runnable = r;
	}
	public synchronized void unsetRunnable(Runnable r) {
		runnable = null;
	}
	public synchronized void _run(CommandInterpreter ci) {
		if(runnable != null) {
			runnable.run();
		} else {
			ci.println("Error, no Runnable available");
		}
	}
	public String getHelp() {
		return "\trun - execute a Runnable service";
	}
}
このクラスはCommandProviderインターフェースを実現しています.これはEquinoxを実行するときに「osgi」のプロンプトで有効なコマンドセットです.Command Providerを書く理由は、コードのインタラクティブ性をテストするのに便利な方法を提供するためです.IBM developerWork上のクリスAniszczyk文章には、より多くのコマンドプロバイダの詳細な議論がある.注意してください.このクラスではOSI APIは何も起動していません.実はorg.osgi.*パッケージから何も導入する必要はありません.私たちが依存しているこのサービスは、この場合、Java.lang.Runnableの一例として、setRunnable方法を通じて提供され、unsetsRunnable方法を使ってそれを持ち帰ります.これは依存注入の形だと考えられます.他の二つの方法は、getHelpと_runはコマンド供給器のために実現されます.そうです.「run」は面白い名前です.下線で始まるのですが、それはEquinoxコンソールAPIの変な特性だけで、OGiやDeclarative Serviceは何もしません.下線先頭モードを使う方法は、Equinoxコンソールでコマンドになりますので、_runの方法は命令「run」を追加しました.また、このクラスについては、ルビンブルルフィールドがスレッドセキュリティで更新され、アクセスできるようにする必要があります.スレッドの安全はOGiにおいてかなり重要であり、これは本質的にマルチスレッドであるからである.率直に言って、私達はいつも私達のコードをスレッドに書いて安全です.以前と同じように、XMLファイルを提供する必要があります.これらはDS声明を含んでいます.OGI-INF/commandprovider 1.xmlからあなたのplug-inプロジェクトにコピーします.
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<component name="commandprovider1">
	<implementation class="org.example.ds.SampleCommandProvider1"/>
	<service>
		<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
	</service>
	<reference name="RUNNABLE"
		interface="java.lang.Runnable"
		bind="setRunnable"
		unbind="unsetRunnable"
		cardinality="0..1"
		policy="dynamic"/>
</component>
これは私たちが前回述べたうっかりしたもう一つの重要なステップです.(Seamus Vensassieの指摘に感謝します.)あなたはbuild.propertiesファイルをあなたのplug-inプロジェクトに編集して、OGI-INFフォルダが選択されているかどうかを確認する必要があります.BundeleがEclipseの導出ガイドを使用してエクスポートするときは、フォルダが中に含まれるか、PDE Buildを使用して確立されることを保証しなければならない.次の行をBundeleのmanifestに追加します.
1
Service-Component: OSGI-INF/commandprovider1.xml
この定義は、私たちが前に見た同じ2つの要素、implemenationとserviceノードがあります.implementノードはコンポーネントを実装するクラスの名前を提供し、serviceノードはDSにサービスのようにこのコンポーネントを登録するように教えます.このような状況の下で私達はCommandProviderインターフェースに登録しました.これはEquinoxコンソールに私達のコマンド提供器の存在を知る方法です.次のノードはreferenceといいます.これまで見たことがないです.DSに対して私たちのコンポーネントは一つのサービスに依存していると宣言しました.name属性は、依存する名前の任意の文字列(私たちはまだこれが何をするか心配していません)であり、interface属性は、私たちが依存するインターフェースの名前を指定します.bind属性は、サービスが有効であるときに実現されるクラスの一つの方法名を呼び出し、言い換えれば、Runnableサービス用Service Registryが登録されたときに、DSはこの新しいサービスの引用を取得し、この指定された方法を使用してコンポーネントに提供する.同じunbind属性は、私たちが使っているサービスが無効になった時にDSで呼び出されます.Cadinality属性はDSの本当の強さを示しています.この属性制御は、この依存性がオプションまたは必要であり、単独または複数であるかどうか.可能な値は以下の通りです
原文を引用する:
?0.1:オプションと単一、「0または1」?1.1:あるのは一つだけ、「一つだけ」?0.n:オプションと複数、「0から複数」?1.n:必須または複数、「0から複数」または「少なくとも1つ」
この例ではオプションと単一を選択して、依存サービスが無効になる場合に対処できるようにコマンドプロバイダを意味します.帰ってきてみますnメソッドのコードは、nullの状況を確認するために処理する必要があります.このBundeleを実行したら何が起こるか見てみましょう.もしあなたのSimpleExport Bundeleが前回から存在しているなら、コマンドラインのプロンプトに「run」を入力すると、次のような応答が見られます.
1
Hello from SampleRunnable
よかったです今回は、前回の授業で書いたRunnableサービスの導入に成功しました.今は「stop」コマンドを使ってSampleExportのBundeleをクローズしてみます.再度「run」コマンドを入力すると、見られます.
1
Error, no Runnable available
DSお知らせの意味は、Runnableサービスがなくなりました.unsetRunnableを呼び出しました.cardinalityのプロパティを見てみてください.もし私たちが「1.1」に変更したら、何が起こると思いますか?例えば、オプションから必要な依存関係に切り替えることができますか?Equinoxを再起動してみます.もしSampleExportのBunleがアクティブであれば、私たちは「run」を入力した後に、以前と同じ情報「Hello from SampleRunnable」を見ます.しかし、もしSampleExportがアクティブでないなら、私たちは以前とは違ったエラー情報を見ることになります.実際には、Equinoxのコンソールヘルプ情報を見ます.これは識別されていないコマンドに対する標準応答です.これは私達の命令が他の自分を提供するという意味です.すでにDSでログアウトしました.コンポーネントに必要な依存があるまでは、DSはサービスの提供をキャンセルするしかありません.逆に言えば、Equinoxコンソールは「run」コマンドを忘れました.あなたはpolicy属性に対しておかしいと感じるかもしれませんが、今はまだ言及していません.この値は「static」または「dynamic」のいずれかであり、このコンポーネントがサービスの動的な切り替えに対応できるかどうかを指摘する.動的でない場合は、ターゲットサービスが変更される度に、DSのためにコンポーネントを元に戻す必要があり、新しいインスタンスを作成します.あなたが望むように、これはヘビー級の方法に相当します.いつでも可能な動的な切り替えをサポートするために、あなたのコンポーネントを符号化したほうがいいです.残念なことにデフォルトはstaticですので、dynamicとして明確に設定してください.オプションのシングルと一つしかないものを見ましたが、どれが多重依存ですか?Service Registryの中にもう一つのRunnableが存在するかもしれません.もし私たちがそれらの中の一つだけを結びつけて選択したのは任意です.現在登録されているRunnableを実行するために、「runall」コマンドを実行するのが好きかもしれません.もし私たちがcardinalityを「0.n」に変えたら何が起こりますか?ある態様では、DSは、setRunnable方法を1回だけ呼び出す代わりに、RegistryのRunnableのインスタンスごとにsetRunnableを呼び出すことになる.問題は私たちが書いたクラスが混乱することです.別のRunnableフィールドを設定する代わりに、Runnableをセットに保存する必要があります.ここの種類のバージョンは細かい変化があります.もう一回コピーしてあなたのプロジェクトのSrcフォルダに貼り付けます.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package org.example.ds;
 
import java.util.*;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
 
public class SampleCommandProvider2 implements CommandProvider {
 
	private List<Runnable> runnables =
		Collections.synchronizedList(new ArrayList<Runnable>());
	
	public void addRunnable(Runnable r) {
		runnables.add(r);
	}
	public void removeRunnable(Runnable r) {
		runnables.remove(r);
	}
	public void _runall(CommandInterpreter ci) {
		synchronized(runnables) {
			for(Runnable r : runnables) {
				r.run();
			}
		}
	}
	public String getHelp() {
		return "\trunall - Run all registered Runnables";
	}
}
OGI-INF/commandprovider 2.xmlを作成し、以下の内容をコピーします.
1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<component name="commandprovider2">
	<implementation class="org.example.ds.SampleCommandProvider2"/>
	<service>
		<provide interface="org.eclipse.osgi.framework.console.CommandProvider"/>
	</service>
	<reference name="RUNNABLE"
		interface="java.lang.Runnable"
		bind="addRunnable"
		unbind="removeRunnable"
		cardinality="0..n"
		policy="dynamic"/>
</component>
最終的にこのファイルをmanifestのService-componentに追加します.このように見えます.
1
2
Service-Component: OSGI-INF/commandprovider1.xml,
  OSGI-INF/commandprovider2.xml
この声明は前のように不可欠であり、私たちはbindとunbind方法に対して名前を変更し、cardinalityを「0.n」に変更する以外にも必要である.練習のように、いくつかの追加のRunnableサービスを登録してみて、「runall」コマンドの実行を確認します.今度、cardinalityを「1.n」に変えたら、何が起こると思いますか?あなたの想像を検証してみます.