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

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

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

OSGi for Beginners翻訳(5:Last)

Running our Bundles in another OSGi Container 他のOSGiコンテナで上記サンプルバンドルを動作させる。


One of the strengths of OSGi is, of course, the "platform neutrality" of the containers, much as Java EE modules are supposedly deployable to any compatible containers. Let's take just a moment to show our bundles described above being deployed in Felix - Apache's OSGi container - just to show how the bundles look in another container. Felix asks you to name a configuration, so it can reload it if you use the name again - we'll call ours "tutorial01" since this is, after all, a tutorial.


OSGiの強みの一つは、もちろんコンテナの「プラットフォームニュートラル」であることです。

JavaEEモジュールが互換性のあるコンテナであれば配備可能であるといわれているのとほとんど同じです。

ちょっと時間をとって、バンドルを他のコンテナで見つける方法を示すためだけに

上記で説明したバンドルをApacheOSGiコンテナであるFelixに

デプロイするところを見てみましょう。

Felixは、設定の名前を尋ねてきますので、同じ名前を使えば再呼び出しができます。

我々の作ったものを、これからこのチュートリアルの間、

"tutorial01"と呼ぶことにしましょう。

$ java -jar bin/felix.jar

Welcome to Felix.
=================

Enter profile name: tutorial01

DEBUG: WIRE: 1.0 -> org.ungoverned.osgi.service.shell -> 1.0
DEBUG: WIRE: 1.0 -> org.osgi.service.startlevel -> 0
DEBUG: WIRE: 1.0 -> org.apache.felix.shell -> 1.0
DEBUG: WIRE: 1.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 1.0 -> org.osgi.service.packageadmin -> 0
DEBUG: WIRE: 2.0 -> org.apache.felix.shell -> 1.0
DEBUG: WIRE: 2.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 3.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 3.0 -> org.osgi.service.obr -> 3.0
DEBUG: WIRE: 3.0 -> org.apache.felix.shell -> 1.0
-> install file:///workspaces/osgi/tutorial/tutorialbundle.jar
Bundle ID: 7
-> start 7
DEBUG: WIRE: 7.0 -> org.osgi.framework -> 0
Apr 18, 2008 10:46:37 AM tutorial.TutorialActivator start
INFO: started
Apr 18, 2008 10:46:37 AM baselib.BaseService sayHello
INFO: Hello, world!
-> install file:///workspaces/osgi/tutorial/repositorybundle.jar
Bundle ID: 8
-> start 8
DEBUG: WIRE: 8.0 -> org.osgi.util.tracker -> 0
DEBUG: WIRE: 8.0 -> org.osgi.framework -> 0
RepositoryService Activated
-> install file:///workspaces/osgi/tutorial/samplebundle.jar
Bundle ID: 9
-> start 9
DEBUG: WIRE: 9.0 -> org.osgi.framework -> 0
DEBUG: WIRE: 9.0 -> module;bundle-symbolic-name="repository";bundle-version="1.0.0" -> 8.0
Apr 18, 2008 10:47:08 AM sample.SampleActivator start
INFO: /foo/bar/baz stored.
-> stop 9
Apr 18, 2008 10:47:09 AM sample.SampleActivator stop
INFO: node: path=//foo/bar/baz, author=unknown, created=Fri Apr 18 10:47:07 EDT 2008, source=unknown, data=[this is some content]
-> shutdown
-> RepositoryService Deactivated
Apr 18, 2008 10:47:12 AM tutorial.TutorialActivator stop
INFO: stopped.

An Actual Application, sort of: an IRC Bot具体的なアプリケーション IRC Botのようなもの



It's all very easy to see the sample repository working as a test - but a test isn't very interesting. Let's take our repository one step further, and hook it into an IRC bot. Our IRC bot will use PircBot , mostly because of its trivial API, will join only one channel on one IRC network (irc.freenode.net's, "#pircbot" channel), and will respond to only two external commands: ~set and ~get. ~set will take a path and some text, and will add the text to that path; ~get will retrieve information from that path. As such, it'll be a sort of painfully simple and uncorrectable infobot ; it'll be left as an exercise to the reader to make it more functional.


ここまでで、とても簡単ながらサンプルリポジトリが動作するのを

テストとして確認できました。

しかし、このテストはあまり興味をそそられるものではありません。

そこで、IRC botにつながるもので、より深いステップに行きましょう!

これから作るIRC botは、PricBotを利用します。

主な理由は、その一般的なAPIです。

IRCネットワークの1つだけのチャンネル

irc.freenode.netの"#pircbot"のチャンネル)につなぎます。

そして、~setと~getという2つの外部的なコマンドにのみ反応します。

~setは、パスといくつかのテキストを受け取ります。

そしてそのテキストを、渡されたパスに追加します。

~getは、パスからそのテキスト情報を取り出します。

それ自体では、いわばシンプルすぎて使い物にならないinfobotでしょう。

もっと充実した機能を作ることは、読者の課題として残しておくことにします。



One of the first things we want to do is create a generic way to look up services. This is surely not the best way to do this! There are a lot of different patterns for this sort of thing; this is simply a way to get started quickly, not well. We'll create a ServiceLookup class, and then an implementation of this ServiceLookup for OSGi.


やりたいことの始めの一つは、サービスを探し出す汎用的な方法を作ることです。

これは、確かにやるべきことのベストな方法ではありません。

このようなことをやるための方法は、他にもたくさんのパターンがあります。

これは、すばやく開始するためのシンプルな方法であり、

上手にやるためのものではありません。

ServiceLookupクラスを作り、OSGiのためのServiceLookupの実装を作りましょう。

package service;

public interface ServiceLookup {
    Object getService(String name);
}
package service.osgi;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import service.ServiceLookup;

public class OSGIServiceLookupImpl implements ServiceLookup {
    BundleContext ctx;

    public OSGIServiceLookupImpl(BundleContext ctx) {
        this.ctx = ctx;
    }

    public Object getService(String name) {
        ServiceReference ref = ctx.getServiceReference(name);
        return ctx.getService(ref);
    }
}


Using the OSGIServiceLookupImpl is simple, once it's constructed with the Activator's BundleContext:


OSGIServiceLookupImplを使うのは簡単です。

いったん、ActivatorのBundleContextを使ってインスタンス化します。

package ircbot;

import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import service.osgi.OSGIServiceLookupImpl;

import java.io.IOException;

public class BotActivator implements BundleActivator {
    IRCBot bot = null;

    public void start(final BundleContext context) throws Exception {
        try {
            bot = new IRCBot(new OSGIServiceLookupImpl(context));
            bot.setVerbose(true);
            bot.connect("irc.freenode.net");
            bot.joinChannel("#pircbot");
        } catch (NickAlreadyInUseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IrcException e) {
            e.printStackTrace();
        }
    }


    public void stop(BundleContext context) throws Exception {
        bot.disconnect();
        bot.dispose();
    }
}


All this does is create an IRCBot instance, with a ServiceLookup implementation. Now for the IRCBot itself, in all its primitive glory:


これで、ServiceLookupの実装を使って、

IRCBotインスタンスを作成するところは終わりです。

これで、IRCBotが自分自身で、繁栄をし始める準備ができました。(訳注:??)

package ircbot;

import org.jibble.pircbot.PircBot;
import service.ServiceLookup;
import repository.RepositoryService;
import repository.Node;

public class IRCBot extends PircBot {
    ServiceLookup service;

    public IRCBot(ServiceLookup service) {
        super();
        this.service=service;
        setName("OSGIBot");
    }

    @Override
    protected void onMessage(String channel, String sender, String login, String hostname, String message) {
        String[] command=message.split(" ");
        if(command.length>1 && ("~set".equals(command[0]) || "~get".equals(command[0]))) {
            String path=command[1];

            // we should use a tracker for this!
            RepositoryService repository= (RepositoryService) service.getService(RepositoryService.class.getName());
            if("~set".equals(command[0])) {
                StringBuilder content=new StringBuilder();
                for(int i=2;i<command.length;i++) {
                    content.append(" ");
                    content.append(command[i]);
                }
                Node node=repository.get(path);
                if(node==null) {
                    node=new Node();
                    node.setAuthor(sender);
                    node.setSource("irc");
                }
                node.getContents().add(content.toString().trim());
                repository.put(path, node);
            }
            if("~get".equals(command[0])) {
                Node node=repository.get(path);
                if(node!=null) {
                    int count=0; // will only do two at most, to be polite
                    for(String content:node.getContents()) {
                        if(count++>2) {
                            break;
                        }
                        sendMessage(channel, sender + ": "+content);
                    }
                }
            }
        }
    }
}



And lastly, our MANIFEST.MF, which specifies our classpath (which has to include pircbot.jar), and the activator name ("ircbot.BotActivator"), and the external dependency on "repository":


そして最後は、(pircbot.jarを含んだ)クラスパスや

activatorの名前("ircbot.BotActivator")や

repositoryの外部依存を特定するMANIFEST.MFです。

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: IRCBot Plug-in
Bundle-SymbolicName: ircbot
Bundle-Version: 1.0.0
Bundle-Activator: ircbot.BotActivator
Bundle-Vendor: theserverside.com
Import-Package: org.osgi.framework;version="1.3.0"
Require-Bundle: repository
Bundle-ClassPath: pircbot.jar,.



Installing this bundle and starting it will (noisily) connect to Freenode and join #pircbot. Note that there's no code in there to handle nick collisions; you may want to try to add that yourself, or change the default nickname used. It's also not very good code; anyone can put in anything, and let's just say it wouldn't be too hard to crash in multiple ways. However...


このバンドルをインストールして開始すると、

かましくフリーノードに接続し、pircbotにつながります。

nickの競合(訳注:IRCではnicknameの重複はエラーとなる)を

ハンドルするコードを書いていないことに注意してください。

ほしければ読者が自分で追加するか、初期のnicknameを変更してください。

これまた、とても良いコードとはいえません。

誰もどこにも入れません。

それに、まぁ、いろんなぶっ壊れかたをしにくいともいえません、、しかし…



There's nothing here that says that only the IRCBot can use the repository. Theoretically, a Jabber client could use the same repository (and very nearly the same code for managing the commands.) In fact, this sort of thing is where OSGi shines: the code in the IRCBot to handle commands could itself be contained in a bundle, and the IRCBot would simply let the appropriate bundle manage commands as needed, and they'd look up the repository service whenever the repository was required.


ここでは、IRCBotがrepositoryを使えるだけとしか言えません。

理論上、早口にしゃべるClientは、同じrepositoryを使うことができます。

(そして、コマンドを管理するためのコードは、ほとんど同じコードです。)

実際、このようなものはOSGiを輝かせています。

コマンドのハンドルのためのIRCBotのコードをそれ自身バンドルに含めることができました。

そして、IRCBotは、シンプルに適切なバンドルに必要に応じてコマンドを管理させるでしょう。

IRCBotは、repositoryが必要に応じて、repositoryサービスを検索することができます。


Conclusion まとめ


Hopefully, this has illuminated readers to some of the potential of OSGi, as well as providing a start on how to use it.


願わくば、OSGiのポテンシャルのいくつかを装飾して読み取った人が、

これをどう使えばよいかについても同じように提供してくれればと思います。