レベル: 初級 万仲龍樹・中山清喬・杉田直哉・津田嘉孝, 日本アイ・ビー・エム システムズエンジニアリング株式会社
2007年 5月 25日 Geronimoでオープンソースミドルウェアの柔軟な統合を実現できるなら、独自のミドルウェアも統合できるはず! 今回は、統合の実例として、近年注目を集めるRubyのランタイム環境をGeronimo上に統合してみます。
はじめに
今回はRuby on Geronimo(RoG)*と称し、近年注目を集めるRubyのランタイム環境をGeronimo上で動かしてみます。Javaの強みにリソース管理やセキュリティ管理能力を持つJ2EE環境が挙げられます。そのJ2EEコンテナであるGeronimoで基盤を固め、その上のアプリケーションをRubyで書いてみることに挑戦します。ここで用いる技術は広範におよびます。JavaやWebアプリケーションだけではないGeronimoの使い方に注目してください。
管理方法の選択肢
GBeanを使ってRubyを管理する場合、考えられる管理方法は次の3つです。
- a JRuby*を使う
- b 別プロセスのRubyの起動/停止を管理する
- c RubyをGeronimoのプロセス上で動かす
aの方法は、GBeanを駆使せずともそのまま動きます。次にbの方法でも、GBeanのdoStart()/doStop()のタイミングでプロセスの起動/停止をするだけで簡単すぎます。本稿では大げさにもRuby on Geronimoとうたっていますから、ここではcの方法で実装します。
RoGでのGBean連携
RoGと名づけた今回のサンプルは、どのようにGBeanを利用しているでしょうか。それを一緒に見ていきましょう。なお、サンプルファイルを用意していますので、適宜ダウンロードしてください。
本当に困難だったRoGへの道
RoGでは図1で示すようにHelloServiceアプリケーションを管理するHelloGBeanとRubyランタイムを管理するRubyGBeanを用意しています。そして、HelloGBeanはRubyGBeanのinvokeメソッドを使って間接的にHelloServiceを呼び出しています。その理由はRubyランタイム用スレッド*をRubyGBeanが管理しているからです。
図1. RoGの全体像
RubyGBean
まず、リスト1にRubyGBean.javaの冒頭を示します。1行目で、RubyGBeanがGBeanLifecycleを実装しているのが分かりますが、Invokerも実装しているのが分かると思います。これがGBean間の連携で中心となるインタフェースです。RubyGBeanでは2行目で、委譲先のUniqueThreadInvoker()を生成しています。
リスト1 RubyGBean.javaの冒頭(一部省略)
1: public class RubyGBean implements GBeanLifecycle, Invoker {
2: private static Invoker invoker = new UniqueThreadInvoker();
3: private static final GBeanInfo GBEAN_INFO = createGBeanInfo();
4: private static GBeanInfo createGBeanInfo() {
5: final GBeanInfoBuilder builder = new GBeanInfoBuilder(RubyGBean.class);
6: builder.addInterface(Invoker.class);
7: return builder.getBeanInfo();
8: }
|
リスト2 rubyGBean.plan(一部省略)
1: <configuration ... configId="configure/rubyGBean">
2: <gbean name="gbean/rubyGBean" class="RubyGBean"/>
3: </configuration>
|
HelloGBean
次にHelloGBeanの冒頭です(リスト3)。HelloGBeanもGBeanLifcycleのほかにHelloを実装しています。これはクライアントコードから呼ばれるインタフェースです。ちなみに、GBeanであることを知らなくても良いようにJNDI*経由で取得できるように15行目でContextにバインドしています。
リスト3 HelloGBeanの冒頭(一部省略)
1: public class HelloGBean implements Hello, GBeanLifecycle {
2: private static GBeanInfo createGBeanInfo() {
3: final GBeanInfoBuilder builder = new GBeanInfoBuilder(HelloGBean.class);
4: builder.addAttribute("contextName", String.class, true);
5: builder.addReference("invoker", Invoker.class);
6: builder.addAttribute("objectName", String.class, false);
7: builder.addAttribute("kernel", Kernel.class, false);
8: builder.setConstructor(new String[]{"contextName", "invoker", "objectName", "kernel"});
9: return builder.getBeanInfo();
10: }
11: public HelloGBean(String contextName, Invoker invoker, String objectName, Kernel kernel) {
12: log.debug("parameter objectName: " + objectName);
13: }
14: public synchronized void doStart() throws Exception {
15: GeronimoContextManager.bind(contextName, this);
16: }
|
さて、ここで注目すべきは、5、8、11行目です。これでHelloGBeanを生成するときにInvokerインスタンスが必要であり、第2引数として渡されることを示しています。ほかに6行目で「objectName」、7行目で「kernel」という属性が現れていますが、これは何でしょうか? 実はGeronimoでは、magic属性というものが定義されており、「objectName」は自分自身の(JMX仕様の)ObjectNameを表す文字列、「kernel」はGeronimoのカーネルをそれぞれ取得できる属性です。この属性をプランファイルに書く必要はありません。HelloGBean用のプランファイルはリスト4のようになります。
リスト4 HelloGBean.plan
1: <configuration ..
2: configId="configure/helloGBean"
3: parentId="configure/rubyGBean">
4: <gbean name="gbean/helloGBean" class="HelloGBean">
5: <attribute name="contextName">/sample/helloGBean</attribute>
6: <reference name="invoker">
7: <domain>geronimo.server</domain>
8: <server>geronimo</server>
9: <application>null</application>
10: <module>configure/rubyGBean</module>
11: <type>GBean</type>
12: <name>gbean/rubyGBean</name>
13: </reference>
14: </gbean>
15:</configuration>
|
3行目では、HelloGBeanがRubyGBeanに依存するので親子関係を定義しています。次に注目すべきところとして、6~13行目があります。これはRubyGBeanのObjectNameを書き下したものです。
HelloServlet
ここまでできれば、後はクライアントコードです。これはHelloServlet(リスト5)でHelloインタフェースをlookupするようにしてみました。そのため、geronimo-application.xml(リスト6)、geronimo-web.xml(リスト7)でHelloGBean用のコンフィギュアを親に持つようにしています。
リスト5 HelloServlet.java
public class HelloServlet extends HttpServlet implements Servlet {
private Hello getHello() {
try {
return (Hello) new InitialContext().lookup("geronimo:/sample/helloGBean");
} catch (NamingException e) { throw new RuntimeException(e); }
}
}
|
リスト6 geronimo-application.xml
<application ... configId="sample.enterprize/sample.enterprize"
parentId="configure/helloGBean">
|
リスト7 geronimo-web.xml
<web-app ... configId="sample.web/sample.web" parentId="configure/helloGBean">
|
次回は
いよいよ次回が本連載の最終回となります。連載第3回、第4回、そして今回解説した内容に基づいて実際に手を動かし、挙動を確かめてみましょう。
このページで出てきた専門用語
-
Ruby on Geronimo(RoG)
- Rubyは言わずと知れた純粋なオブジェクト指向言語。RoGは、わたしの冗談に基づく明らかな造語です。
-
JRuby
- Java VM上で動作するRubyランタイム環境。
-
Rubyランタイム用スレッド
- RoGではJNI*を経由し、C/C++のソースコードからRubyを使用しています。しかし、現状、RubyはC言語に提供するメソッドでマルチスレッドをサポートしていないようで、helloメソッドをコールしたスレッドから直接Rubyをコールするのを避けるため、RubyGBeanが単一のWorkerThreadでRubyへアクセスする管理を担っています。
-
JNI
- Java Native Interfaceの略で、C言語で書かれたソースコードを呼び出すことができます。
-
JNDI
- Java Naming and Directory Interfaceの略。Javaでネーミングおよびディレクトリ機能を利用できるようにするAPIです。
参考文献
著者について  | |  | 万仲龍樹・中山清喬・杉田直哉・津田嘉孝
日本アイ・ビー・エム システムズエンジニアリング株式会社
日本アイ・ビー・エム システムズ・エンジニアリング株式会社(ISE)は、日本アイ・ビー・エムグループにおけるSE技術者の専門家集団として1992年7月に設立されました。発足以来、IBM製品を中心とした難易度の高い複雑なシステム構築や先進技術の適用場面において、卓越したITスキルによりお客様と開発現場を支援してきました。近年は、仮想化技術・グリッドコンピューティング・Web 2.0・オープンソースソフトウェア等々の先進技術分野での支援も展開しています。 |
記事の評価
|