レベルエンター山本大のブログ

面白いプログラミング教育を若い人たちに

BLOCKVROCKリファレンス目次はこちら

OSGi for Beginners翻訳(4)

OSGi for Beginners翻訳 第1回(http://d.hatena.ne.jp/iad_otomamay/20080513/p1
OSGi for Beginners翻訳 第2回(http://d.hatena.ne.jp/iad_otomamay/20080514/p1
OSGi for Beginners翻訳 第3回(http://d.hatena.ne.jp/iad_otomamay/20080515/p1

Building our Repository Bundle(リポジトリバンドルを組み立てる)


Now we can work on our repository bundle, which adds some additional functionality in the Activator: it registers the repository as a service and exports it, so that other bundles can use our repository to look stuff up.


さて、先ほど作成したActivatorでの追加の機能を

いくつか追加するリポジトリを動かすことができるようになりました。

他のバンドルがルックアップして、このリポジトリを使用できるように

その追加機能をサービスとしてリポジトリに登録して、エクスポートします。


package repository;

import java.util.Hashtable;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.util.tracker.ServiceTracker;

import repository.impl.XMLRepositoryService;

public class Activator implements BundleActivator {

        /**
         * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
         */
        public void start(BundleContext context) throws Exception {
                // register the service
                context.registerService(
                                RepositoryService.class.getName(),
                                new XMLRepositoryService(),
                                new Hashtable<Object,Object>());

                // create a tracker and track the log service
                ServiceTracker repositoryServiceTracker =
                        new ServiceTracker(context, RepositoryService.class.getName(), null);
                repositoryServiceTracker.open();

                // grab the service
                RepositoryService repositoryService = (RepositoryService) repositoryServiceTracker.getService();
                System.err.println("RepositoryService Activated");
        }

        /*
         * (non-Javadoc)
         * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
         */
        public void stop(BundleContext context) throws Exception {

                // close the service tracker
                System.err.println("RepositoryService Deactivated");
        }
}


Note that this hardcodes the use of our XMLRepositoryService, above, which is a little icky. We could use Spring, or the Service Provider Interface, or an environment variable, or something - even an OSGi preference service - to make this a runtime decision, but that's outside of our scope for this article. Let's get this service deployed and we'll show you how to use it from another bundle, which will itself open the door for other options.


ちょっといやな感じですが、上記では

XMLRepositoryServiceの利用をハードコードしていることに注目してください。

Springまたはサービスプロバイダインターフェイス、または環境変数

またはそのほかの何か(OSGiが選択するサービスでさえ)を使うことができます。

これは、実行時に決定します。しかしこのあたりはこの記事の対象範囲外です。

さあこのサービスを配備して他のバンドルから利用する方法を紹介しましょう。

ここでいう他のバンドルは、それ自身が他のオプションのためにドアを開くものです。


Following our first simple bundle, the relevant information for our repository bundle consists of the manifest file and the directory structure. Here's the directory structure:


はじめの簡単なバンドルに続いて、

先ほどのリポジトリバンドルに関連する情報は、

マニフェストファイルとディレクトリ構成からなります。

以下に、ディレクトリ構成を示します。

$ jar tvf repositorybundle.jar
     0 Thu Apr 17 14:08:46 EDT 2008 META-INF/
   553 Thu Apr 17 14:08:44 EDT 2008 META-INF/MANIFEST.MF
     0 Thu Apr 17 13:57:12 EDT 2008 repository/
     0 Thu Apr 17 13:57:12 EDT 2008 repository/impl/
  1383 Thu Apr 17 13:57:12 EDT 2008 repository/Activator.class
  2095 Thu Apr 17 13:57:12 EDT 2008 repository/Node.class
   205 Thu Apr 17 13:57:12 EDT 2008 repository/RepositoryService.class
   694 Thu Apr 17 13:57:12 EDT 2008 repository/impl/MapRepositoryService.class
  3823 Thu Apr 17 13:57:12 EDT 2008 repository/impl/XMLRepositoryService.class
895924 Thu Apr 17 14:03:40 EDT 2008 xerces-2.4.0.jar
109318 Thu Apr 17 14:05:08 EDT 2008 xml-apis-1.0.b2.jar
431568 Thu Apr 17 13:54:06 EDT 2008 xom-1.1.jar



And the manifest file:


そしてマニフェストファイルは以下です。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Repository Plug-in
Bundle-SymbolicName: repository
Bundle-Version: 1.0.0
Bundle-Activator: repository.Activator
Bundle-Vendor: theserverside.com
Import-Package: org.osgi.framework;version="1.3.0",
 org.osgi.util.tracker;version="1.3.1"
Export-Package: repository;uses:="org.osgi.framework"
Bundle-ClassPath: .,xom-1.1.jar,xerces-2.4.0.jar,xml-apis-1.0.b2.jar



So what did we just do? We built a jar, using the Activator implementation we offered earlier, and this has a number of dependencies: XOM, an implementation of Xerces (because of XOM), and the ServiceTracker API.


ここでは何をしているのでしょうか?

それは、先ほど提供したActivatorの実装や、

XOMやXOMのためのXercesの実装、ServiceTrackerのAPIなど

いくつかの依存性を使うJarを組み立てているのです。



We are also doing one other interesting thing: we're exporting the repository package. This means that other bundles in our OSGi container can import those packages, and look up specific services by name (in this case, the repository is registered under the name of the RepositoryService interface, or "repository.RepositoryService".) We can install this bundle now and start it:


それから、もう一つ面白いことをしましょう。

リポジトリパッケージを出力するのです。

これは、OSGiコンテナのほかのバンドルが、

それらのパッケージをインポートできるということです。

また、名前を特定してインポートしたサービスをルックアップすることができます。

(この場合、repositoryは、RepositoryServiceインターフェイスの名前または

"repository.RepositoryService"の下に登録されています。)

このバンドルを登録して起動することができます。

osgi> install file:///workspaces/osgi/tutorial/repositorybundle.jar
Bundle id is 11

osgi> start 11
RepositoryService Activated

osgi>



This doesn't look all that exciting yet, but we've actually got a working OSGi infrastructure we can leverage now. It should be noted that we're putting our interface in with our implementation. In a perfect world, RepositoryService would be in its own jar, so we can separate the interface and its implementation. This isn't hard, even from a bundle perspective; in the activator for the interface bundle, you'd just do nothing, and in the implementing bundle, you'd import the interface from the other (interface) bundle. We're just not doing it here because it creates a maze of twisty little passages, all alike, and that slows everyone down.



これはまだエキサイティングなものには見えませんが、

実際に動作するOSGiの環境を手に入れていますので、

すぐに利用することができます。

私たちの実装の中に、インターフェイスを設定していることを注意しておかなければなりません。

完璧な世界では、RepositoryServiceは自分自身のJarに含められるべきです。そうすればインターフェイスとその実装を分けることができます。

バンドルの作業上でも、これは難しいことではありません。

インターフェイスのバンドルのためのactivatorでは、

何も設定することはありません、そしてバンドルの実装では、

他の(インターフェイス)バンドルからインターフェイスをインポートする必要があります。

それは曲がりくねった小さな通路の迷路を一様にすべて作成するというような作業であり

皆を減速させることになるので、ここではそんなことはしません。

Using our OSGi Bundle from another Bundle 作成したOSGiバンドルを他のバンドルから利用する


The last step is to build yet another bundle - but this one will look up the repository service and use it.


最後のステップは、さらに他のバンドルを組み立てることです。

しかし、このバンドルはリポジトリサービスをルックアップしてそれを使うことになります。


Let's show the Bundle Activator first. It's really quite simple, and entirely nonfunctional: when the bundle starts, it looks up the RepositoryService, and stores something into the service just to make sure the repository has something in it. It uses the stop() mechanism to actually look something up in the repository and display it on console. This isn't exactly glamorous work, but it's enough to show the process in motion:


さぁ、まずはBundle Activatorを見せましょう。

これは本当にとてもシンプルです。そして完全に無機能です。

バンドルが実行されたときには、それはリポジトリが何かをもっていることを

確認するだけのためにRepositoryServiceをルックアップします。

そしてサービスの中に何かを保存します。

この機能では、実際にリポジトリから何かを探し出して、

コンソールに表示するためにstop()メカニズムを使っています。

これは、それこそ魅力的な作業ではありませんが、

動作の過程をお見せするには、十分です。

package testrepouser;

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

import java.util.logging.Logger;

import repository.Node;
import repository.RepositoryService;

public class SampleActivator implements BundleActivator {
        Logger log=Logger.getLogger(this.getClass().getName());

        /*
         * (non-Javadoc)
         * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
         */
        public void start(BundleContext context) throws Exception {
                ServiceReference ref = context.getServiceReference(
                RepositoryService.class.getName());
                RepositoryService lookup = (RepositoryService) context.getService(ref);
                Node testNode=new Node("this is some content");
                lookup.put("/foo/bar/baz", testNode);
                log.info("/foo/bar/baz stored.");
        }

        /*
         * (non-Javadoc)
         * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
         */
        public void stop(BundleContext context) throws Exception {
                ServiceReference ref = context.getServiceReference(
                RepositoryService.class.getName());
                RepositoryService lookup = (RepositoryService) context.getService(ref);
                log.info(lookup.get("//*/baz"));
        }
}


The MANIFEST.MF file looks like this:


MANIFEST.MF ファイルは以下のようになります。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Repository Sample Plug-in
Bundle-SymbolicName: samplerepouser
Bundle-Version: 1.0.0
Bundle-Activator: sample.SampleActivator
Bundle-Vendor: theserverside.com
Import-Package: org.osgi.framework;version="1.3.0"
Require-Bundle: repository



The last line stands out. If you look at the RepositoryService's manifest, the symbolic name there is... "repository." Here, we're saying that this bundle should be able to access exported classes from whatever bundle is referred to here - in other words, since our repository bundle exports the "repository" package, our SampleActivator can import the repository classes directly from the repository bundle instead of having to package them itself.


最後の行が目立ちますね。RepositoryServiceのマニフェストを見るなら、そこにある象徴的な名前は、"repository"です。

ここでは、このバンドルが、ここから呼び出されるどんなバンドルからも、

エクスポートしているクラスにアクセスできるべきだと宣言しています。

言い換えれば、"repository"のパッケージをrepositoryバンドルがエクスポートしてからは、

SampleActivatorは、それら自体をパッケージしなければならない代わりに

repositoryバンドルから、直接repositoryクラスをインポートすることができます。



We build our sample.jar bundle, which should look like this:


sample.jarバンドルを以下のように組み立てます。

$ jar tvf ../samplebundle.jar
     0 Thu Apr 17 14:47:48 EDT 2008 META-INF/
   421 Thu Apr 17 14:47:46 EDT 2008 META-INF/MANIFEST.MF
     0 Thu Apr 17 14:47:48 EDT 2008 sample/
  1270 Thu Apr 17 14:47:48 EDT 2008 sample/SampleActivator.class



Note the simplicity here: there's nothing in the bundle except our activator. There are no service implementations, not even the interface.


シンプルさに注目してみてください、ここでは我々のactivator以外のバンドルはありません。

サービスの実装もなく、インターフェイスさえありません。



We can install the sample bundle, start it, then stop it, to show everything happening:


サンプルバンドルをインストールできます。

開始して、終了すると発生した処理がすべて表示されます。

osgi> install file:///workspaces/osgi/tutorial/samplebundle.jar
Bundle id is 17

osgi> start 17
Apr 17, 2008 2:49:07 PM sample.SampleActivator start
INFO: /foo/bar/baz stored.

osgi> stop 17
Apr 17, 2008 2:49:09 PM sample.SampleActivator stop
INFO: node: path=//foo/bar/baz, author=unknown, created=Thu Apr 17 14:49:07 EDT 2008, source=unknown, data=[this is some content]

osgi>