今回作成するのは、ブラウザ上でメッセージを入力して送信すると、サーバー上でメッセージを記録するだけの簡単なアプリケーションです。ただし、具体的なメッセージの記録方式は将来の拡張に備えて柔軟に変更可能にしておく必要があります。
簡単のため、メッセージの記録方式は以下の通りとします。
- バージョン1.0では、送信されたメッセージを標準出力にそのままダンプします。
- バージョン2.0では、送信されたメッセージをテキストファイルに記録します。
このような拡張に対応するため、アプリケーションをモジュール(OSGiバンドル)に分解してみましょう。OSGiにおけるベスト・プラクティスを参照すると、典型的な分解方法は以下のようになることが分かります。
ここではベスト・プラクティスに従い、API(Javaのinterface)を提供するパッケージと実装を別のバンドルに分離しています。矢印はエクスポートとインポートの組合せによるバンドル間の依存関係を示しますので、MessageLogger-APIバンドルがMessageLogger-ImplバンドルとMessageLogger-Webバンドルに共通のインターフェースを提供していることが分かります。
また、MessageLogger-WebとMessageLogger-Implの間にある黄色の三角形はOSGiサービス・レジストリー経由の参照を示しており、両者の間には直接の参照関係はありません。そのため、クライアントであるMessageLogger-Webを修正することなく、後でMessageLogger-Implを入れ替えることができます。
アプリケーションを効率よく実装するためには、Enterprise OSGiに対応したメタデータやBlueprint定義ファイルの作成などを支援してくれるツールがあると便利です。今回は、無償で提供されている「IBM Rational Development Tools for OSGi Applications(以下、RDT for OSGiと表記)」を利用します。
RDT for OSGiは、Eclipse 3.6にEnterprise OSGi開発支援機能を追加するプラグインです。本記事ではインストール方法の詳細説明は割愛させていただきますので、こちらを参照して各自で開発環境を準備して下さい。
また、アプリケーションを実行するには、Enterprise OSGiに対応したランタイム(アプリケーション・サーバー)が必要です。本記事では、ランタイムとしてWebSphere Application Server V7にFeature Pack for OSGi Applicationsを適用した環境を利用することを想定しています。ランタイムのセットアップ方法については、本連載の第1回を参照してください。
Enterprise Bundle Application(EBA)作成
RDT for OSGiのセットアップが終わったら、新しくワークスペースを作成してください。
まず初めに、EBAプロジェクトを作成します。これは、従来のJavaEEにおけるEARプロジェクトに相当するもので、複数のアプリケーション・コンポーネント(バンドル)をまとめて管理するためのコンテナです。
「File – New – OSGi Application Project」を選択し、「Project Name」を指定(名称は任意ですがここでは仮にMessageLoggerとします)して「Finish」をクリックします。
共通で参照されるAPIを提供するバンドルを実装します。
「File – New- OSGi Bundle Project」を選択してください。
「Project Name」をMessageLogger-APIとします。「Application membership」の項目で先ほど作成したEBAに追加するためのチェックが入っていることを確認し、「Finish」をクリックします。
プロジェクトが作成できたら、以下の通りJava Interfaceを新規作成します。
[MessageService.java]
package dw.example.messagelogger.api;
import java.util.Date;
public interface MessageService {
public void recordMessage(String mes, Date ts);
public void startUp();
}
|
次に、このInterfaceを含むパッケージをエクスポートして、他のバンドルが参照できるようにします。プロジェクトの直下にある「Manifest: MessageLogger-API」をダブルクリックして、Manifestファイル・エディターを開きます。
Runtimeタブを開き、Exported Packagesセクションの「Add...」をクリックして”dw.example.messagelogger.api”パッケージを追加します。
さらに、「Properties...」をクリックするとバージョン指定のダイアログが表示されますので、”1.0.0”を入力します。
MANIFEST.MFタブを開くと、先ほど入力した内容がOSGiメタデータとして反映されていることが確認できます。
Export-Package: dw.example.messagelogger.api;version="1.0.0"
|
このように、RDT for OSGiを利用することでOSGiメタデータの定義を容易に行うことができます。内容を確認したら、Ctrl-S等でファイルを保存してください。
APIの実装を提供するバンドルの初期バージョンを実装します。
「File – New- OSGi Bundle Project」を選択してください。
「Project Name」をMessageLogger-Implとします。「Application membership」の項目で先ほど作成したEBAに追加するためのチェックが入っていることを確認し、「Finish」をクリックします。
プロジェクトを作成したら、まずAPIバンドルを参照するためにインポートの設定を行います。プロジェクトの直下にある「Manifest: MessageLogger-Impl」をダブルクリックして、Manifestファイル・エディターを開き、Dependenciesタブを開きます。
Imported Packagesセクションの「Add...」をクリックして ”dw.example.messagelogger.api(1.0.0)” を追加し、Ctrl-S等でファイルを保存してください。
プロジェクトが作成できたら、以下の通りJava Classを新規作成します。(MessageServiceインターフェースの追加をお忘れなく。)
[MessageServiceImpl.java]
package dw.example.messagelogger.server;
import java.util.Date;
import dw.example.messagelogger.api.MessageService;
public class MessageServiceImpl implements MessageService {
@Override
public void recordMessage(String mes, Date ts) {
System.out.println("[MessageService] " + mes
+ " (TimeStamp=" + ts + ")");
}
@Override
public void startUp() {
System.out.println(">> MessageService Start.");
}
}
|
次に、この実装クラスをOSGiサービス・レジストリーに登録するための設定を行います。Enterprise OSGiでは、サービス・レジストリーへの登録を宣言的に行うためBlueprintサービスが仕様化されており、XMLを作成してOSGI-INF/blueprintに配置すればOSGiフレームワークがサービスの管理を行ってくれます。
RDT for OSGiではBlueprint定義ファイルの作成支援機能も提供しています。MessageLogger-Impleプロジェクトを右クリックし、「New – Other」を選択してウィザードの「OSGi」を展開し、「Blueprint File」を選択すると空の定義ファイル(デフォルトではblueprint.xml)が作成されます。
XMLファイルに<bean>と<service>を追記します。
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
<bean id="messageservice"
class="dw.example.messagelogger.server.MessageServiceImpl"
init-method="startUp">
</bean>
<service ref="messageservice"
interface="dw.example.messagelogger.api.MessageService" />
</blueprint>
|
ここでは、<bean>で実装クラスを指定し、<service>で公開するインターフェース型を指定してサービス・レジストリーに登録しています。
ユーザー・インターフェースとなるWebアプリケーションを提供するバンドルを実装します。
「File – New- OSGi Bundle Project」を選択してください。
「Project Name」をMessageLogger-Webとします。「Configration」をOSGi Web Configurationとし、「Application membership」の項目で先ほど作成したEBAに追加するためのチェックが入っていることを確認して「Finish」をクリックします。
プロジェクトを作成したら、先ほどと同様にAPIバンドルを参照するためのインポートの設定を行います。Manifestファイル・エディターを開き、Dependenciesタブから”dw.example.messagelogger.api(1.0.0)” を追加してください。
次に、以下の通りServletを新規作成します。
[ReceiverServlet.java] (doGetメソッドのみ修正)
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String mes = (String) request.getParameter("mes");
Date ts = new Date();
try {
InitialContext ic = new InitialContext();
MessageService service
= (MessageService) ic.lookup("osgi:service/"
+ MessageService.class.getName());
service.recordMessage(mes, ts);
} catch (NamingException e) {
e.printStackTrace();
}
PrintWriter pw = response.getWriter();
pw.println("<html><body>");
pw.println("<h2>Message Recorded.</h2><hr/>");
pw.println("<h3>message: " + mes + "</h3>");
pw.println("<h3>timestamp: " + ts + "</h3>");
pw.println("</body></html>");
pw.flush();
}
|
MessageServiceのインスタンスを取得する処理は、JNDIに対して”osgi:service/”という名前空間でlookupを行うことで、OSGiフレームワークに登録されているサービスを取得しています。これは、Enterprise OSGiが提供するJavaEEとOSGiの連携機能によるものです。
最後に、このServletにリクエストを送るJSPをindex.jspとしてWebContentの直下に作成してください。
[index.jsp]
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Message Logger Service</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/ReceiverServlet">
メッセージ:<input name="mes" type="text" value=""></input><br/>
<input type="submit" value="送信"></input>
</form>
</body>
</html>
|
ここまでの作業で一通りアプリケーションの実装が完了したので、アプリケーションをEBAファイルとしてエクスポートしWebSphere Application Server(WAS)にデプロイします。
最初に作成したEBAプロジェクト(MessageLogger)を右クリックし、「Export – OSGi Application(EBA)」を選択します。
エクスポート先を指定し、「Finish」をクリックします。
次に、WASを起動し、管理コンソールを開きます。
「アプリケーション - アプリケーション・タイプ – アセット」を選択し、「インポート」をクリックしてEBAファイルをアップロードします。(詳細設定はデフォルトのままでかまいません。)
「アプリケーション - アプリケーション・タイプ – ビジネス・レベル・アプリケーション」を選択し、「新規作成」をクリックして、「名前」をMessageLoggerとします。
「適用」をクリックした後、「デプロイ済みアセット」セクションで「追加 – アセットの追加」を選択します。
アップロード済みのEBAを選択して追加します。設定内容はデフォルトのままでかまいませんが、必要に応じてコンテキスト・パスなどを適宜変更してください。
ビジネス・レベル・アプリケーションの一覧からMessageLoggerアプリケーションを開始し、ブラウザでhttp://localhost:9080/MessageLogger-Web/ を開きます。
メッセージを入力して送信ボタンをクリックすると、以下のような送信結果画面が表示されます。(エラーが発生した場合は、SystemOut.logなどを確認の上、ソースコードの記述ミスがないか確認してみてください。)
メッセージ送信サービスのVer 1.0.0では、メッセージは標準出力にそのままダンプしているだけですので、入力した内容がWASのSystemOut.logに出力されているはずです。
[SystemOut.log]
[10/10/25 6:25:01:484 JST] 00000017 SystemOut
O [MessageService] test test (TimeStamp=Mon Oct 25 06:25:01 JST 2010)
|
それでは、サービスの実装を変更してみましょう。
「File – New- OSGi Bundle Project」を選択して、新しいサービス・バンドルを作成します。
「Project Name」をMessageLogger-Impl-2.0.0とします。今回は単体のバンドルとして作成しますので、「Application membership」の項目でEBAに追加するためのチェックを外してから「Finish」をクリックします。
APIバンドルのインポート設定や、Javaクラスの実装、Blueprint定義ファイルの作成などはVer 1.0.0と同様に行ってください。(新規作成が面倒であればコピー&ペーストしていただいてもかまいません。)
Manifestファイルの「Overview」タブを開き、「General Information」セクションでIDおよびNameをMessageLogger-Implに、バージョンを2.0.0.qualifierに変更します。
recordMessage()の実装を修正し、受信したメッセージをユーザーホームディレクトリの”messages.log.txt”に記録するようにします。
[MessageServiceImpl.java]
public void recordMessage(String mes, Date ts) {
String home = System.getProperty("user.home");
FileWriter writer = null;
try {
writer = new FileWriter(
new File(home + "/messages.log.txt"), true);
writer.write(
"[MessageService] " + mes +
" (TimeStamp=" + ts + ")\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
|
プロジェクトMessageLogger-Impl-2.0.0を右クリックし、「Export – OSGi Bundle」を選択します。エクスポート先を指定して「Finish」をクリックします。
次に、WASの管理コンソールを開きます。
「環境 – OSGi bundle repository – 内部 bundle repository」を選択し、「新規作成」をクリックしてjarファイル(OSGiバンドル)をアップロードします。
「アプリケーション - アプリケーション・タイプ – アセット」を選択し、EBAをクリックして詳細画面を表示します。
画面右側にある「追加プロパティー」セクションで、「このアプリケーションにおけるbundleバージョンの更新」を選択します。
MessageLogger-Implの「新規バージョン」ドロップダウンリストから、2.0.0を選択して「プレビュー」をクリックします。
入れ替え後のバンドルが依存関係を満たすことを確認して、「コミット」をクリックします。
バンドルの入れ替えはアプリケーション再起動後に反映されますので、ビジネス・レベル・アプリケーションを一旦停止し、再度起動した後にWebアプリケーションからメッセージを送信してみてください。<user.home>/messages.log.txt(Windows XPの場合はc:\Documents and Settings\<user>\messages.log.txt) に記録されるはずです。
今回は、簡単なサンプル・アプリケーションを題材として、Enterprise OSGiの機能を利用したアプリケーションのモジュール化について解説してきました。OSGiの特徴を生かして保守性の高いアプリケーションを構築するためには、適切なモジュール分割と、OSGiサービスによる間接的な参照関係を活用することが重要ですが、そのエッセンスはお伝えできたのではないかと思います。
エンタープライズOSGi入門の連載は今回で終了となりますが、ご紹介しきれなかった内容がまだまだ沢山残っています。どこかでまたお会いできる機会があれば幸いです。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| サンプル・アプリケーション(完成版) | MessageLogger.zip | 9KB | HTTP |
学ぶために
-
IBM Rational Development Tools for OSGi Applications, Version 1.0
-
WebSphere Application Server でエンタープライズ OSGi アプリケーションを開発する
-
OSGiアプリケーションを開発、利用するためのベスト・プラクティス
-
OSGi Alliance
-
My developerWorks Groups:OSGiファン
-
developerWorks Japan:WebSphere Application Server:WebSphere Application Server の技術情報サイト
-
WebSphere Application Server 製品情報
製品や技術を入手するために

