Spring Roo 入門: 第 3 回 Spring Roo のアドオンを開発する

Spring Roo は、アプリケーション (主に Web アプリケーション) を素早く簡単に構築できるようにする RAD ツールです。Spring Roo の内部では OSGi アドオン・アーキテクチャーをベースとしているため、アドオンを追加することによって Spring Roo を簡単に拡張することができます。Spring Roo にはアドオンを作成するためのコマンドが用意されています。作成したアドオンを Spring Roo ユーザー・コミュニティーで使用できるように公開するのも極めて簡単です。この記事では、まず Spring Roo のアーキテクチャーについて概説し、Spring Roo がその独自のアドオン・アーキテクチャーを利用して各種の機能を提供する仕組みを説明します。その後、Roo シェルを使ってアドオンを作成し、ニーズに合わせて変更する方法を紹介します。

Shekhar Gulati, Senior Consultant, Xebia

Shekhar Gulati は、Xebia India の Java コンサルタントです。これまで 6 年以上、Enterprise Java の経験があり、Spring、Spring-WS、Spring Roo など、一連の Spring プロジェクトに関する幅広い経験を持っています。彼が関心を持っている分野には、Spring、NoSQL データベース、Hadoop、Spring Roo のような RAD フレームワーク、クラウド・コンピューティング (主に Google App Engine、CloudFoundry、OpenShift などの PaaS サービス) などがあります。彼は執筆活動も活発に行っていて、JavaLobby、Developer.com、IBM developerWorks、そして彼自身のブログ (http://whyjava.wordpress.com) などに寄稿しています。Twitter で彼をフォローするには、http://twitter.com/#!/shekhargulati にアクセスしてください。



2011年 10月 07日

はじめに

連載「Spring Roo 入門」では、第 1 回第 2 回にわたり、Spring Roo を使って一から本格的なエンタープライズ・アプリケーションを構築しました。この最初の 2 回の記事では、Spring Roo のアプリケーション開発環境を使用して短時間で Web アプリケーションを構築する方法に焦点を当て、JPA、Selenium テスト、Spring Security、E メールの統合、Spring Roo のソーシャル機能、データベース・リバース・エンジニアリングなど、多数の機能を紹介しました。今回焦点を当てるのは、Spring Roo のアドオン・アーキテクチャーです。アドオン・アーキテクチャーの概要を説明した後、addon create コマンドを使用して Spring Roo のアドオンを作成する方法を紹介します。この記事を読み終える頃には、Spring Roo のアドオンを素早く簡単に作成できるようになっているはずです。


Spring Roo のアドオン・アーキテクチャー

最も単純な形のアドオンは、特定の機能をソフトウェア・アプリケーションに追加するソフトウェア・コンポーネントです。例えば、ほとんどの Web ブラウザーでは、アドオンによって動画サポートを提供しています。また、Eclipse (多くの Java 開発者が実際に使用しているか、少なくとも知っているオープンソースの IDE) もその一例で、JUnit サポート、SVN サポートなど、その機能の多くはアドオンによって提供されています。ここではアドオンという言葉を、プラグインおよび拡張機能を総称する用語として使用しています。

Spring Roo でのアドオンの概念には、以下のものも含まれます。

  1. サード・パーティーの開発者が Spring Roo の機能を拡張できるようにするためのもの
  2. Spring Roo が新しい機能を追加しやすくするためのもの
  3. Spring Roo を小さな魔法使いにとどめておくためのもの (つまり、Spring Roo のサイズを抑えるということ)

Spring Roo の論理コンポーネント

Spring Roo は、2 つの論理部分に分けられます。

Spring Roo のコア・コンポーネント: アドオン開発を可能にするために、Spring Roo では、各種のアドオンをホストする実行環境を形成する一連のコア・コンポーネントを用意しています。用意されているコア・コンポーネントには、まずクラスパス (Classpath) があります。クラスパス (Classpath) はプロセス・マネージャー (Process manager) とシェル (Shell) をサポートします。プロセス・マネージャー (Process manager) はプロジェクト (Project) およびファイル操作取り消し (File undo) をサポートします。プロジェクト (Project) はモデル (Model)、メタデータ (Metadata)、およびファイル・モニター (File monitor) をサポートします。さらに、これらのコンポーネントのすべてが共通して使用するサポート (Support) コンポーネントがあります。図 1 に、以上のコア・コンポーネントの関係を図示します。

図 1. Spring Roo のコア・コンポーネント
Spring Roo コンポーネント間の関係を示す図

以下に、上記の図に示されているコア・モジュールについて説明します。

  • サポート (Support)org.springframework.roo.support モジュールは、すべてのコア・モジュールおよびアドオンで共通して使用するユーティリティー・クラスを提供します。これらのユーティリティー・クラスには、AssertFileCopyUtilsXmlUtilsStringUtilsFileUtils などがあります。例えば、あるファイルの内容を別のファイルにコピーしたい場合には、FileCopyUtils が自動的にコピーしてくれます。
  • メタデータ (Metadata) — org.springframework.roo.metadata モジュールは、依存関係の登録およびキャッシングが組み込まれたメタデータ・サービス・プロバイダーのインターフェースおよび実装を提供します。
  • ファイル・モニター (File monitor) — org.springframework.roo.file.monitor モジュールは、ファイルシステムの変更が検出されると、イベントをパブリッシュします (デフォルト実装では自動調整ディスク・ポーリングを使用します)。
  • ファイル操作取り消し (File undo) — org.springframework.roo.file.undo モジュールは、プロセス・マネージャーが使用するファイル操作取り消し機能を提供します。
  • プロジェクト (Project) — org.springframework.roo.project モジュールは、Apache Maven や Apache Ant などの一般的なエンド・ユーザー・プロジェクト・ビルド・システムを抽象化します。
  • プロセス・マネージャー (Process manager) — org.springframework.roo.process.manager モジュールは、ACID のようなファイルシステム抽象化を提供します。この抽象化には、ディスク・ロールバックとプロセス同期が含まれます。
  • クラスパス (Classpath) — org.springframework.roo.classpath モジュールは、Java および AspectJ コンパイル・ユニットの抽象構文ツリーの構文解析および型バインディングを実行します。

Spring Roo の基本アドオン: Spring Roo の機能はいずれもアドオンによって提供されます。Roo V1.1.3 に同梱されている基本アドオンを以下に記載します。

  • アドオン・クリエーター — org.springframework.roo.addon.creator アドオンを使用すると、サード・パーティーは Roo アドオンを容易に作成できるようになります。
  • バックアップ — org.springframework.roo.addon.backup アドオンを使用して「backup」と入力すると、ZIP ファイルの形でバックアップが作成されます。
  • Cloud Foundry — org.springframework.roo.addon.cloud.foundry アドオンを使用すると、VMware Cloud Foundry がサポートされるようになります。
  • 構成機能 — org.springframework.roo.addon.configurable アドオンを使用すると、AspectJ ITD による Spring の @Configurable アノテーションの導入がサポートされます。
  • データベース・リバース・エンジニアリング — org.springframework.roo.addon.dbre アドオンを使用すると、既存のデータベースのインクリメンタル・リバース・エンジニアリングがサポートされます。
  • データ・オンデマンド — org.springframework.roo.addon.dod アドオンを使用すると、結合テストで使用するサンプル・データの自動作成がサポートされます。
  • E メール — org.springframework.roo.addon.email アドオンを使用すると、Spring の E メール・サポートをターゲット・プロジェクトに統合して構成できるようになります。
  • エンティティー — org.springframework.roo.addon.entity アドオンを使用すると、Java Persistence API @Entity クラスの自動保守が広範にサポートされます。
  • 動的ファインダー — org.springframework.roo.addon.finder を使用すると、コード補完対応のタイプ・セーフな JPA 問い合わせ言語ファインダーを作成できるようになります。
  • Git — org.springframework.roo.addon.git アドオンを使用すると、プロジェクトにおける GIT の統合がサポートされます。これにより、コマンドが正常に完了するたびに、ローカル GIT リポジトリーに自動的にコミットされます。
  • GWT — org.springframework.roo.addon.gwt アドオンを使用すると、Google Web Toolkit を使用した UI の scaffold 生成がサポートされます。
  • JavaBean — org.springframework.roo.addon.javabean アドオンを使用すると、@RooJavaBean アノテーションが設定されたクラスの JavaBean ゲッター/セッターの自動保守が行えるようになります。
  • JDBC — org.springframework.roo.addon.jdbc アドオンを使用すると、さまざまなバンドルに同梱された JDBC ドライバーに対する OSGi 準拠のアクセスをカプセル化することが可能になります (主に他のアドオンが使用)。
  • JMS — org.springframework.roo.addon.jms アドオンを使用すると、ターゲット・プロジェクトにおける Java Messaging System 設定の構成がサポートされます。
  • JPA — org.springframework.roo.addon.jpa アドオンを使用すると、指定された JPA プロバイダーのインストールと、そのプロバイダーに応じた JDBC のセットアップが可能になります。
  • JSON — org.springframework.roo.addon.json アドオンを使用すると、JSON 関連のシリアライズおよびデシリアライズ・メソッドを POJO に追加できるようになります。
  • ロギング — org.springframework.roo.addon.logging アドオンを使用すると、コマンドごとのログ・レベルの構成を含め、Log4j のセットアップが可能になります。
  • 複数形変換 — org.springframework.roo.addon.plural アドオンを使用すると、名詞を複数形に変換できるようになります (主に他のアドオンが使用)。
  • プロパティー・エディター — org.springframework.roo.addon.property.editor アドオンを使用すると、Spring MVC の必要に応じてプロパティー・エディターを管理できるようになります。
  • プロパティー・ファイル — org.springframework.roo.addon.propfiles アドオンを使用すると、ターゲット・プロジェクトでのプロパティー・ファイルの管理がサポートされるようになります。
  • RooBot クライアント — org.springframework.roo.addon.roobot.client アドオンを使用すると、RooBot サーバーを介したアドオン管理のサポートが提供されます。
  • セキュリティー — org.springframework.roo.addon.security アドオンを使用すると、ログイン・ページ、フィルター、および依存関係を含め、Spring Security がセットアップされます。
  • シリアライズ — org.springframework.roo.addon.plural アドオンを使用すると、要求された Java 型に対する java.io.Serializable サポート (UID 保守など) が追加されます。
  • Solr — org.springframework.roo.addon.solr アドオンを使用すると、ターゲット・プロジェクトでの Apache Solr 機能の構成および統合がサポートされます。
  • 結合テスト — org.springframework.roo.addon.test アドオンを使用すると、プロジェクト・エンティティーの JUnit 結合テストが生成できるようになります。
  • ToString — org.springframework.roo.addon.tostring アドオンを使用すると、@RooToString アノテーション付きのあらゆるクラスに対し、有効な toString() メソッドを生成できるようになります。
  • WebFlow — org.springframework.roo.addon.web.flow アドオンを使用すると、ターゲット・プロジェクトでの Spring Web Flow 機能の構成および統合をサポートできるようになります。
  • Web MVC コントローラー — org.springframework.roo.addon.web.mvc.controller アドオンを使用すると、ターゲット・プロジェクトでの Spring MVC コントローラーの構成および統合がサポートされるようになります。
  • Web MVC 組み込み — org.springframework.roo.addon.web.mvc.embedded アドオンを使用すると、MVC アドオンを拡張して、地図や動画などの組み込み機能を Web ページに追加できるようになります。
  • Web MVC JSP — org.springframework.roo.addon.web.mvc.jsp アドオンを使用すると、ターゲット・プロジェクトで Spring MVC JSP 機能を構成および統合できるようになります。
  • Selenium — org.springframework.roo.addon.web.selenium アドオンを使用すると、ターゲット・プロジェクトで Selenium Web テストを構成および統合できるようになります。

Spring Roo のコア・コンポーネントと付属の基本アドオンについて説明したところで、ここからは、独自のアドオンの作成に取り掛かります。


OSGi ランタイム環境

Spring Roo がベースとしているのは、Roo のアドオン・アーキテクチャーに最適な OSGi です。OSGi は、モジュール単位で組み込むサービス指向のアプリケーションを開発するには非常に優れたインフラストラクチャーとなります。

Roo シェルは、Apache Felix をその OSGi ランタイム・フレームワークとして使用し、コンポーネントの管理には SCR (Service Component Runtime) を、バンドルの解決には OBR (OSGi Bundle Repository) を使用します。Roo シェルには、さまざまな OSGi コマンドが用意されています。これらのコマンドは、「help osgi」と入力すると一覧表示することができます (リスト 1 を参照)

リスト 1. OSGi に対する Roo の help コマンド
roo> help osgi 
* osgi find - Finds bundles by name 
* osgi framework command - Passes a command directly 
through to the Felix shell infrastructure 
* osgi headers - Display headers for a specific bundle 
* osgi install - Installs a bundle JAR from a given URL 
* osgi log - Displays the OSGi log information 
* osgi obr deploy - Deploys a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr info - Displays information on a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr list - Lists all available bundles from the 
OSGi Bundle Repository (OBR) system 
* osgi obr start - Starts a specific OSGi Bundle Repository (OBR) bundle 
* osgi obr url add - Adds a new OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url list - Lists the currently-configured 
OSGi Bundle Repository (OBR) repository file URLs 
* osgi obr url refresh - Refreshes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi obr url remove - Removes an existing 
OSGi Bundle Repository (OBR) repository file URL 
* osgi ps - Displays OSGi bundle information 
* osgi resolve - Resolves a specific bundle ID 
* osgi scr config - Lists the current SCR configuration 
* osgi scr disable - Disables a specific SCR-defined component 
* osgi scr enable - Enables a specific SCR-defined component 
* osgi scr info - Lists information about a specific SCR-defined component 
* osgi scr list - Lists all SCR-defined components 
* osgi start - Starts a bundle JAR from a given URL 
* osgi uninstall - Uninstalls a specific bundle 
* osgi update - Updates a specific bundle 
* osgi version - Displays OSGi framework version

Spring Roo のアドオン作成コマンド

Spring Roo は、各種のアドオンを作成するためのアドオン作成コマンドがあらかじめバンドルされて提供されます。addon create コマンドを公開するアドオン・クリエーターも、Roo のアドオンの 1 つです。Roo では現在、以下の 4 つのタイプのアドオンをサポートしています。

  1. 国際化対応アドオン — Roo の scaffold で生成した Spring MVC アプリケーションに言語翻訳を追加できるようにします (例えば、ヒンディー語の翻訳を追加するなど)。
  2. シンプル・アドオン — シンプル・アドオンでは、プロジェクトの依存関係または構成、あるいはその両方に多少の変更を加えることができます (例えば、JAR や Maven プラグインを追加して maven pom.xml を変更するなど)。
  3. アドバンスド・アドオン — 力仕事を行うこのアドオンは、Java コードの作成が必要となる本格的な Spring Roo アドオンを作成する場合に使用します (例えば、ドメイン・オブジェクトの equals および hashcode メソッドを作成可能なアドオンを作成するなど)。これらの機能を提供するアドオンは、すでにコミュニティー・アドオンにあります。
  4. ラッパー・アドオン — このアドオンは、OSGi 対応のバンドルを作成するために Maven 成果物をラップします。アドオンがその機能を完成するためには依存関係が必要となる場合には、このタイプのアドオンが必要です。例えば、Spring Roo のデータベース・リバース・エンジニアリング・アドオンがそのタスクを完了するには Postgres JDBC ドライバーが必要なため、このアドオンを使用して Postgres JDBC ドライバーをラップすることになります。

これらのアドオンは、以下の新しいアドオンを作成することによって、Roo アドオン開発を容易にするためのコマンドを作成します。

httppgp://

Roo シェルでダウンロードされて起動されるソフトウェアに署名する開発者として、どの開発者を信頼するかをユーザーが指定できるように、Spring Roo V1.1 には PGP (Pretty Good Privacy) が導入されました。実際、Roo のあらゆるリリースには現在 PGP 署名が適用されています。URL にも PGP による公平な署名が使用できることを示すために、Roo には httppgp:// という新しいプロトコル・ハンドラーが導入されています。これにより、オープンな形のセキュリティーで、悪意のあるダウンロードからユーザーを守れるようになっています。これらの標準により、スタンドアロンの PHP ツールを使用して Roo の操作を独立して検証することも可能になります。

  • Google Code での SVN ソース・コード管理と統合されたアドオン
  • Google Code プロジェクトの一部として作成され、公開 Maven リポジトリーでホストされるアドオン
  • RooBot に準拠したアドオン。RooBot は、VMware でホストされているサービスで、公開 Roo OBR ファイルの重要なコンテンツに索引を付けます。OBR ファイルは、バンドル・メタデータの XML ベースの表現です。RooBot に準拠するためのアドオンの要件には以下に挙げるものがあります。
    1. OSGi に準拠していること
    2. 公開鍵を持つ PGP 署名付き成果物であること
    3. httppgp:// プロトコルによって登録されていること

Roo の addon create コマンドを使用すれば、以上のすべての要件を満たすアドオンが自動的に構成されます。したがって、アドオンを作成して外部に公開するまでにかかる時間が短縮されるというわけです。

アドオンの作成を始める前に、実際に機能する Spring Roo 環境が用意されていることを確認してください。Spring Roo のインストール手順は、この連載の第 1 回に記載されています。


ヒンディー語のサポートが必要な場合 (i18N アドオンの作成)

Spring Roo で Spring MVC ベースの Web アプリケーションを作成するときには、web mvc language コマンドを使って、各国語のサポートを追加することができます。Spring Roo であらかじめサポートされている言語は、英語、ドイツ語、スペイン語、イタリア語、オランダ語、スウェーデン語です。国際化に対応するための Web MVC JSP アドオンは、JSPX ファイルを webapp ディレクトリーに配置すると使用できるようになります。JSPX ファイルは、単純な JAR ベースのアプリケーションを Spring MVC Web アプリケーションに変換するコントローラー・コマンドによって生成されます。

インド人である私は、作成した Web アプリケーションにヒンディー語のサポートを追加することにしました。Spring Roo に用意されている addon create i18n コマンドは、web mvc install language コマンドを拡張して、ヒンディー語などの新しい言語のサポートを追加します。このコマンドに必要なのは、目的の言語で翻訳された messages.properties ファイルのみです。

Spring Roo は Spring MVC Web アプリケーションを作成するときに、application.properties と messages.properties という 2 つのプロパティー・ファイルを作成します。application.properties ファイルにはアプリケーションに固有のプロパティー (アプリケーション名など) が格納されます。一方、messages.properties ファイルに格納されるプロパティーは特定のアプリケーションに固有のものではありません。例えば、削除ボタンをクリックすると表示される「Are you sure want to delete this item? (この項目を削除しますか?)」というようなメッセージや、ログイン、ログアウトなどの際に表示されるメッセージが、このファイルに格納されます。したがって、i18n アドオンを作成するには、messages.properties ファイルの翻訳バージョンが必要になるというわけです。

Spring Roo でのデフォルトの国際化対応について説明したので、これからヒンディー語のサポートを追加するための i18n アドオンを作成します。Google Code にプロジェクトをセットアップする方法、コマンドを使用してアドオンを作成する方法、作成したアドオンを外部に公開してリリースする方法、そして最後にアドオンを RooBot サービスに登録する方法を説明します。RooBot サービスへの登録は重要です。RooBot サービスに登録すると、RooBot がアドオンに索引を付けるため、他の開発者が addon search コマンドで検索したときに、そのアドオンが表示されます。

プロジェクトのセットアップ

Spring Roo のドキュメントに、Google Code にプロジェクトと Maven リポジトリーをセットアップする方法が詳しく説明されているので、ここで説明を繰り返すことはしません。このプロジェクトの名前には「roo-hind-addon」を使用するとだけ言っておきます。

i18N アドオンを作成する

プロジェクトをセットアップした後には、roo-hindi-addon という名前の空のディレクトリーが作成されています。このディレクトリーに移動して、roo コマンドを実行してください。シェルがアクティブになったら、「addon create i18n」と入力します。Tab キーを押すと、このコマンドが取る 7 つの属性が表示されます。このうち、必須の属性は、topLevelPackage (新規アドオンの最上位レベルのパッケージ)、locale (イタリア語を表す「it」など、ロケールの略語)、messageBundle (message_xx.properties への完全修飾パス。ここで、xx はロケール名です) の 3 つです。残りの 4 つの属性はオプションで、language は言語の完全な名称、flagGraphic は xx.png ファイルへのフル・パス (ここで、xx はフラグの名前)、description はアドオンの説明、projectName はプロジェクトの名前 (指定しない場合は、最上位レベルのパッケージ名が使用されます) を指定します。projectName 属性は指定することをお勧めします。projectName 属性の値には、Google Code でホストされるプロジェクトの名前を設定してください。この例の場合、値には roo-hindi-addon を設定することになります。

上記の属性のうち、最も重要なのは、翻訳された messages.properties ファイルを指定する messageBundle です。messages.properties をヒンディー語に翻訳するのに最も簡単な方法は、Google 翻訳などのサービスを利用して各プロパティーを 1 つずつ変換した後、messages_hi.properties に書き込むことですが、この例の場合には使用できません。その理由は、Java プロパティー・ファイルが使用する ISO-8859-1 エンコード方式では、ヒンディー語の文字をサポートしていないからです。この問題を克服するために、私は Eclipse ResourceBundle Editor という Eclipse プラグインを使用しました。このプラグインを使えば、さまざまな言語用に翻訳したリソース・バンドルを作成することができます。Eclipse ResourceBundle Editor は、http://www.nightlabs.de/updatesites/development/ 更新サイトからインストールすることができます。messages.properties から messages_hi.properties ファイルへの変換については、この記事では取り上げません。ResourceBundle Editor プラグインは簡単に使用することができます。注意していただきたいことは、対象とする言語の文字がサポートされていたら、ResourceBundle Editor を使用する必要はなかったということです。リスト 2 に、messages_hi.properties ファイルの例を示します。

リスト 2. messages_hi.properties ファイルの例
button_cancel = \u0930\u0926\u094D\u0926 
button_end = \u0905\u0902\u0924
button_find = \u0916\u094B\u091C\u0947\u0902
button_home = \u0918\u0930 
...

ファイル全体を見るには、ここをクリックしてください。翻訳済み messages_hi.properties ファイルの準備が完了すれば、後はたった 1 つのコマンドを入力するだけでアドオンを作成することができます。リスト 3 のコマンドを Roo シェルに入力すると、ヒンディー語のアドオンを作成することができます。

リスト 3. ヒンディー語のアドオンを作成するコマンド
addon create i18n --locale hi --topLevelPackage org.xebia.roo.addon.i18n.hindi 
  --messageBundle <location to messages_hi.properties> \
--language hindi --projectName roo-hindi-addon 
  --flagGraphic <full path to flag hi.png>

リスト 4 に、上記の addon create i18n コマンドによる成果物を記載します。

リスト 4. 作成された成果物
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/messages_hi.properties 
Created SRC_MAIN_RESOURCES/org/xebia/roo/addon/i18n/hindi/hi.png 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi 
Created SRC_MAIN_JAVA/org/xebia/roo/addon/i18n/hindi/HindiLanguage.java

上記のコマンドによって生成された Maven プロジェクトは、Eclipse にインポートすることも (m2eclipse を使用)、「File (ファイル)」 > 「Import (インポート)」 > 「Maven」 > 「Existing Maven projects (既存の Maven プロジェクト)」を順に選択することで SpringSource Tool Suite にインポートすることもできます。しかし、このプロジェクトの場合にはアドオンに変更を加える必要がないため、インポートする必要はありません。

今度は、完成したアドオンをインストールして、プロジェクトで使用し、外部に公開する作業に取り掛かります。けれどもその前に、生成されたコードをより深く理解できるように、成果物について説明しておきます。

  • pom.xml — このファイルは、標準 Maven プロジェクト構成です。生成された pom.xml には各種の構成済みプラグインがあり、PGP を使用した成果物への署名付与、Maven リリース・プラグインを使用したアドオンのリリース、そして Maven バンドル・プラグインを使用したOSGi バンドルの作成に関連する作業を行えるようになっています。アドオンを Roo シェル内部で実行するために必要な OSGi および Felix 依存関係をプロジェクトに追加するのも、このファイルの役目です。
  • assembly.xml — Maven アセンブリー・プラグインは、このファイルが定義する構成を使用して、アドオンをパッキングします。
  • messages_hi.properties — このファイルは、アドオンの作成中に私たちが提供したメッセージ・バンドル・ファイルです。このファイルは、リソース・フォルダーにコピーされます。
  • hi.png — このファイルは、アドオンの作成中に私たちが提供したフラグ PNG ファイルです。このファイルも、リソース・フォルダーにコピーされます。
  • HindiLanguage.java — このファイルは、作成したアドオンによって作成された唯一の Java ファイルです。このファイルは、特定の言語に対応する情報を取得するために使用されます。例えば、ここにはロケール名、メッセージ・バンドル・リソース・ファイルなどが指定されます。

ヒンディー語のサポートをアプリケーションに追加する

ここからは、今までの説明で作成したアドオンを使用してアプリケーションにヒンディー語のサポートを追加する方法を説明します。

  1. Roo シェルを終了して、mvn clean install コマンドを実行します。ビルド・プロセスの実行中に、GPG パスフレーズの入力を求められます。
  2. Roo アドオンのビルドが完了したら、新しいコマンドラインを開き、i18n-hindi-client という名前のディレクトリーを作成します。ここに、アドオンの単純なクライアントを作成します。
  3. i18n-hindi-client ディレクトリーに移動して、roo コマンドを入力します。
  4. Roo シェルで以下のコマンドを実行します。これにより、単純な Spring MVC Web アプリケーションが作成されます。
    リスト 5. MVC Web アプリケーションを作成する Roo コマンド
    project --topLevelPackage com.shekhar.roo.i18n.client \
    --projectName i18n-hindi-client  
    persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY  
    entity --class ~.domain.MyUser  
    field string --fieldName name --notNull  
    controller all --package ~.web
  5. コマンドとして「web mvc language --code de en es it nl sv」と入力し、Tab キーを押します。

    ヒンディー語サポートは表示されません。これは、ヒンディー語のアドオンをまだインストールしていないためです。

  6. アドオンをインストールするには、以下の内容を入力します。
    osgi start --url file:///<location to addon target 
       folder>/org.xebia.roo.addon.i18n.hindi-0.1.0.BUILD-SNAPSHOT.jar

    上記のコードによって、Spring Roo ヒンディー語アドオンがインストールされてアクティブになります。アドオンのステータスは、osgi ps コマンドを使用して確認することができます。このコマンドを実行すると、以下のように OSGi バンドル情報とそのステータスが表示されます。

    [ 95] [Active ] [ 1] roo-hindi-addon (0.1.0.BUILD-SNAPSHOT)
  7. もう一度、「web mvc language –code」と入力して Tab キーを押します。今度は、ヒンディー語に対応するコードが表示されるはずです。「hi」コードを選択すると、ヒンディー語サポートがアプリケーションに追加されます。
    web mvc language –code hi
  8. Roo シェルを終了して、「mvn tomcat:run」と入力すると、フッターにインドの国旗が表示されます。この国旗をクリックすることで、アプリケーションはヒンディー語で表示されるようになります (図 2 を参照)。
    図 2. ヒンディー語のサポート
    ブラウザーで実行中のアプリケーションのスクリーン・ショット。テキスト項目がヒンディー語で表示されています。

開発システムでアドオンが正常に機能していることをテストした後は、前に作成した Google Code プロジェクトにこのアドオンを送信してください。

内部での動作

作成したアドオンは正常に機能することがわかったところで、インディー言語がアプリケーションで使用できるようになった仕組みを調べてみましょう。

  1. osgi start コマンドによって、roo-hindi-addon が起動されました。
  2. アドオンが起動すると、addon create i18n コマンドによって作成された HindiLanguage クラスが i18nComponent に登録されます。このコンポーネントは、i18n アドオンを登録および登録解除するための OSGi サービス・リスナーです。登録された HindiLanguage クラスは、Apache Felix で提供されている @Component アノテーションと @Service アノテーションでマーキングされます。この 2 つのアノテーションにより、コンポーネントとサービスが Roo シェルに登録されて使用可能な状態になります。
  3. web mvc install language –code コマンドを入力して Tab キーを押すと、Tab 補完サービスが i18nComponent クラスの getSupportedLanguages() メソッドを呼び出し、このメソッドによって i18n アドオンの java.util.Set が返されます。HindiLanguage は i18nComponentに登録済みなので、このクラスも返されたというわけです。

アドオンを外部に公開する

アドオンを外部に公開するのは簡単です。なぜなら、Roo の create コマンドが必要な Maven プラグインをすべてインストールして、作業の大部分を終わらせているからです。プロジェクトのルート・ディレクトリーに移動して、リスト 6 のコマンドを入力してください。

リスト 6. Roo プロジェクトを公開する
svn add pom.xml src/ legal/ readme.txt 
svn commit -m "Roo Hindi Addon first version" 
mvn release:prepare release:perform

Maven リリース・プラグインから、リリース・バージョン、タグ名、開発バージョンの入力を求められますが、単純にデフォルト設定を選択して先に進んでください。成果物が Google Code プロジェクトにリリースされて公開されるまでには数分かかります。この処理が完了すると、アドオンが Google Code プロジェクトに表示されます。

アドオンを RooBot に登録する

プラグインをリリースした後は、そのプラグインを s2-roobot@vmware.com に E メールで送信することで、アドオン・リポジトリーにプラグインを登録することができます。E メールの件名の行には、repository.xml ファイルが含まれていなければなりません。例えば、先ほど作成したアドオンの場合、repository.xml は http://code.google.com/p/roo-hindi-addon/source/browse/repo/repository.xml となります。RooBot への登録についての詳細は、Spring Roo のドキュメントを参照してください。


Java アプリケーションをモニターしたい場合 (シンプル・アドオンの作成)

アプリケーションのパフォーマンスのボトルネックを判別するために Java アプリケーションをモニターすることは、多くのエンタープライズ・アプリケーションに共通している要件です。私が作成したアプリケーションもその例外ではなかったため、この要件に対処するために利用できるオープンソースのソリューションを探すことにしました。Java Application Monitor (JAMon) は簡単に本番アプリケーションをモニターできる、無料でパフォーマンスに優れたスレッド・セーフの Java API です。

JAMon サポートを Web アプリケーションに追加するには、以下のことが必要です。

  1. jamon JAR を pom.xml に追加すること。
  2. アプリケーションのコンテキスト・ファイル内に JamonPerformanceMonitorInterceptor Bean を定義すること。リスト 7 に、この Bean 定義の一例を記載します。
リスト 7. JamonPerformanceMonitorInterceptor コード
	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value>speakerController</value> 
				<value>talkController</value> 
			</list> 
		</property> 
	</bean>

この Bean 定義は、どんな開発者でも簡単に記憶できるようなものではないので、この定型的な構成を自動化できるとしたら言うことありません。そこで私が思い立ったのは、JAMon 依存関係を追加して、インターセプター Bean を作成するというプロセスを自動化できるアドオンを作成することです。しかし、シンプル・アドオンとアドバンスド・アドオンのどちらが必要なのかは、どのように判断すればよいのでしょうか。

  1. Maven 依存関係または構成成果物、あるいはその両方をプロジェクトに追加する必要がある場合には、シンプル・アドオンを使用します。
  2. プロジェクトで既存の Java 型を拡張するか、新しい Java 型と AspectJ ITD を導入する必要がある場合、あるいはその両方を必要とする本格的なアドオンを作成する必要がある場合には、アドバンスド・アドオンを使用します。

JAMon サポートを追加するための要件は、jamon.jar をクラスパスに追加して、Bean 定義を格納するアプリケーション・コンテキスト・ファイルを作成することです。この場合、既存のコンテキスト・ファイルを使用するよりも、新しい Spring アプリケーション・コンテキスト・ファイルを作成するほうが、アプリケーション・コンテキストのモジュール化に役立つため、賢明と言えます。これらの要件を考えると、JAMon サポートを任意の Web アプリケーションに追加できるシンプル・アドオンを作成するべきであることは明らかです。

プロジェクトのセットアップ

今回のプロジェクトも、国際化対応アドオンのセットアップで行ったようにセットアップする必要があります。このプロジェクトは、「pring-roo-addon-jamon」と名付けます。

シンプル・アドオンを作成する

プロジェクトのセットアップが完了すると、.svn フォルダーだけが含まれる spring-roo-addon-jamon という名前のディレクトリーが作成されているはずです。spring-roo-addon-jamon ディレクトリーに移動して、Spring Roo シェルを起動したら、以下のコマンドを実行してください。

addon create simple --topLevelPackage org.xebia.roo.addon.jamon \
--projectName spring-roo-addon-jamon

アドオンを作成するために必要な作業は、たったこれだけです。

生成されたアドオンをインストールする

アドオンをインストールするには、以下のコマンドを使用します。

osgi start --url file://<Location to addon
    target folder>/org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

アドオンをインストールした後は、テストのために、i18n アドオン用に作成したような単純なクライアントを作成します。生成されたアドオンは、以下の 2 つのコマンドを提供します。

  1. say hello」。Roo シェルにウェルカム・メッセージを出力するコマンドです。このコマンドは常に使用できるので、Roo シェルを実行している間、いつでも入力することができます。
  2. web mvc install tags」。Web アプリケーションの scaffold によって生成されるデフォルトの MVC タグを置き換えるためのコマンドです。このコマンドは、Web アプリケーションを作成してからでないと使用することができません。

生成されたコードの内容

アドオンのテストが終わったところで、このアドオンによって生成されたファイルを調べてみましょう (リスト 8 を参照)。

リスト 8. spring-roo-addon-jamon 用に生成されたファイル
Created ROOT/pom.xml 
Created ROOT/readme.txt 
Created ROOT/legal 
Created ROOT/legal/LICENSE.TXT 
Created SRC_MAIN_JAVA 
Created SRC_MAIN_RESOURCES 
Created SRC_TEST_JAVA 
Created SRC_TEST_RESOURCES 
Created SRC_MAIN_WEBAPP 
Created SRC_MAIN_RESOURCES/META-INF/spring 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonCommands.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperations.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonOperationsImpl.java 
Created SRC_MAIN_JAVA/com/shekhar/roo/addon/jamon/JamonPropertyName.java 
Created ROOT/src/main/assembly 
Created ROOT/src/main/assembly/assembly.xml 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/info.tagx 
Created SRC_MAIN_RESOURCES/com/shekhar/roo/addon/jamon/show.tagx

生成された pom.xml、assembly.xml、LICENSE.TXT、および readme.txt は、i18n アドオンで生成された成果物と同じです。これらのファイルについてはすでに説明したので、ここでもう一度繰り返すことはしません。今回注目すべき成果物は、JamonCommands、JamonOperations、JamonOperationsImpl、および JamonPropertyName です。シンプル・アドオン・コマンドによって生成されるコードを理解するために、これらのファイルについて個別に説明します。

  1. JamonCommands.java:JamonCommands — このクラスは、CommandMarker というマーカー・インターフェースを実装し、say hello と web mvc install tags という 2 つのコマンドを公開します (リスト 9 を参照)。
    リスト 9. JamonCommands.java:JamonCommands から生成されたコード
    @Component 
    @Service 
    public class JamonCommands implements CommandMarker { 
            
           @Reference private JamonOperations operations; 
            
           @Reference private StaticFieldConverter staticFieldConverter; 
    
    
           protected void activate(ComponentContext context) { 
               staticFieldConverter.add(JamonPropertyName.class); 
               } 
    
    
           protected void deactivate(ComponentContext context) { 
                   staticFieldConverter.remove(JamonPropertyName.class); 
           } 
            
           @CliAvailabilityIndicator("say hello") 
           public boolean isSayHelloAvailable() { 
                   return true; 
           } 
            
           @CliCommand(value = "say hello", 
    help = "Prints welcome message to the Roo shell") 
           public void sayHello( 
                   @CliOption(key = "name", mandatory = true, 
    help = "State your name") String name, 
                   @CliOption(key = "contryOfOrigin", mandatory = false, 
           help = "Country of origin") JamonPropertyName country) { 
                    
                   log.info("Welcome " + name + "!"); 
                   log.warning("Country of origin: " + (country == null ? \
    JamonPropertyName.NOT_SPECIFIED.getPropertyName() : country.getPropertyName())); 
                   
                   log.severe("It seems you are a running JDK " 
    + operations.getProperty("java.version")); 
                   log.info("You can use the default JDK logger anywhere in your" 
    + " add-on to send messages to the Roo shell"); 
           } 
            
           @CliAvailabilityIndicator("web mvc install tags") 
           public boolean isInstallTagsCommandAvailable() { 
                   return operations.isInstallTagsCommandAvailable(); 
           } 
            
           @CliCommand(value = "web mvc install tags", 
    help="Replace default Roo MVC tags used for scaffolding") 
           public void installTags() { 
                   operations.installTags(); 
           } 
    }

    コードが冗長にならないように、コード・ジェネレーターによって生成されたコメントはすべて削除しました。以下で、このクラスの重要なメンバーについて説明します。

    1. CommandMarker — すべてのコマンド・クラスに共通する要件は、CommandMarker インターフェースを実装し、@Component および @Service アノテーションを付けることによって、それぞれのコマンド・クラスのコマンドを Roo シェルで使用可能にすることです。@Reference アノテーションが付いたフィールドは、JamonCommands クラスの依存関係で、Roo OSGi コンテナーによって注入されます。@Component および @Service アノテーションが付いたクラスはいずれも、他のアドオンに注入することができます。
    2. 起動および起動停止メソッドactivate メソッドと deactivate メソッドは、それぞれ addon install コマンドでアドオンをインストールするとき、addon remove コマンドでアドオンを削除するときに呼び出されるメソッドです。この 2 つのメソッドによってアドオンのライフサイクルに接続すると、Roo OSGi コンテナーによってそのライフサイクルが管理されます。
    3. @CliAvailabilityIndicator アノテーションが付けられたメソッド@CliAvailabilityIndicator アノテーションが付けられたメソッドは、コマンドが使用可能でないときに、そのコマンドを非表示にするためのメソッドです。例えば、Spring Security をプロジェクトにインストールする security setup コマンドは、プロジェクトが Web アプリケーションになるまでは表示されません。このようなメソッドを使用することは必須ではありませんが、ユーザーがその特定の時点で意味のないコマンドを起動できないようになるという点では役に立ちます。例えば、ユーザーが Web アプリケーションを使用できるようになる前に security setup コマンドを実行しても、何の意味もありません。
    4. @CliCommand アノテーションが付けられたメソッド@CliCommand アノテーションが付けられたメソッドは、コマンドを Roo シェルに登録します。@CliCommand には 2 つの属性があります。1 つはコマンド名を定義する value、もう 1 つは、help コマンドを入力すると表示されるヘルプ・メッセージを定義する help です。すべてのコマンドは、コマンドの一部として示される @CliOption アノテーションを使用して、必須属性とオプション属性を定義することができます。例えば、say hello コマンドには name という必須属性と、country というオプション属性があります。
  2. JamonOperationsImpl.java — コマンド・クラスは、コマンドの実行時に何らかの処理を行わなければなりません。これらの処理は、処理実行クラスによって行われます。JamonOperationsImpl は、依存関係を pom.xml に追加したり、リソースを目的の場所にコピーしたりするなどの実際の作業を引き受ける処理実行クラスです。JamonOperationsImpl クラスはその処理を行うために、Spring Roo フレームワークが提供するコア・サービスを使用します。例えば、依存関係を追加する場合には、ProjectOperations インターフェースを使用します。ファイルをコピーする場合には、FileManager インターフェースを使用します。JamonOperationsImpl クラスのコードを見ると、Roo アドオンをさらに深く理解することができます (リスト 10 を参照) 。
    リスト 10. JamonOpertionsImpl
    	@Component 
    	@Service 
    	public class JamonOperationsImpl implements JamonOperations { 
    		private static final char SEPARATOR = File.separatorChar; 
    	 
    		@Reference private FileManager fileManager; 
    		@Reference private ProjectOperations projectOperations; 
    
    		public boolean isInstallTagsCommandAvailable() { 
    			return projectOperations.isProjectAvailable() &&
                fileManager.exists(projectOperations.getProjectMetadata().
    			getPathResolver().getIdentifier(Path.SRC_MAIN_WEBAPP,
                    "WEB-INF" + SEPARATOR + "tags")); 
    	} 
    
    		public String getProperty(String propertyName) { 
    			Assert.hasText(propertyName, "Property name required"); 
    			return System.getProperty(propertyName); 
    		} 
    
    		public void installTags() { 
    			PathResolver pathResolver =
                projectOperations.getProjectMetadata().getPathResolver(); 
    			createOrReplaceFile(pathResolver.getIdentifier(
    			    Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                        "tags" + SEPARATOR + "util"), "info.tagx"); 
    
    		createOrReplaceFile(pathResolver.getIdentifier(
    			Path.SRC_MAIN_WEBAPP, "WEB-INF" + SEPARATOR +
                    "tags" + SEPARATOR + "form"), "show.tagx"); 
    		} 
    	 
    		private void createOrReplaceFile(String path, String fileName) { 
    			String targetFile = path + SEPARATOR + fileName; 
    			MutableFile mutableFile = fileManager.exists(targetFile) ?
                    fileManager.updateFile(targetFile) :
                    fileManager.createFile(targetFile); 
    			    try { 
    			    	FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
                            fileName), mutableFile.getOutputStream()); 
    			    } catch (IOException e) { 
    				throw new IllegalStateException(e); 
    			} 
    		} 
    	}

    JamonOperationsImpl クラスには、2 つの重要なメソッドが含まれています。それは、コマンドが使用可能であるかどうかをチェックする isInstallTagsCommandAvailable メソッド、そしてターゲット・プロジェクトにタグをインストールする installTags メソッドです。これらの処理を実行するために、JamonOperationsImpl クラスは Spring Roo の以下のコア・サービスとユーティリティーを使用します。

    1. ProjectOperations: JamonOperationsImpl クラスは、この ProjectOperations サービスを使用して、プロジェクトが使用可能であるかどうかをチェックし、tags フォルダーのパスを取得します。
    2. FileManager: JamonOperationsImpl クラスは、この FileManager サービスを使用して、ファイルが特定のパスに存在するかどうかをチェックし、ファイルの更新を取得するか、MutableFile を新規に作成します。MutableFile も Roo に固有のクラスで、変更可能なファイルへのハンドルを表します。
    3. TemplateUtils: TemplateUtils ユーティリティー・クラスは、アドオン・バンドルに含まれるテンプレート・ファイル (info.tagx および show.tagx) への InputStream を獲得するために使用されます。
    4. FileCopyUtils: FileCopyUtils ユーティリティー・クラスは、(TemplateUtils の) テンプレートを (FileManager の) MutableFile にコピーするために使用されます。

要件を満たすようにアドオンを変更する

シンプル・アドオンに関する最初のセクションでは、このアドオンが任意の Spring MVC Web アプリケーションで JAMon を構成できるようにするために満たさなさなければならない 2 つの要件を説明しました。これらの要件は、以下のとおりです。

  1. JAMon JAR を pom.xml に追加すること。
  2. アプリケーションのコンテキスト・ファイル内に JamonPerformanceMonitorInterceptor Bean を定義すること

この 2 つの要件を満たすために、これから JamonCommands クラスを以下のように変更して、jamon setup コマンドがサポートされるようにします。その後、要件を満たすための実際の作業を行う、jamon setup コマンドに対応する 1 つの処理を追加します。

JamonCommandsJamonCommands クラスには、2 つだけメソッドを持たせます。1 つは jamon setup コマンドが使用可能であるかどうかをチェックする isInstallJamon、もう 1 つは、jamon setup コマンドの起動に応じて JAMon をインストールする installJamon です (リスト 11 を参照)。

リスト 11. JamonCommands のコード
@Component 
@Service 
public class JamonCommands implements CommandMarker { 
	 
	private Logger log = Logger.getLogger(getClass().getName()); 

	@Reference private JamonOperations operations; 
	 
	@CliAvailabilityIndicator("jamon setup") 
	public boolean isInstallJamon() { 
		return operations.isInstallJamonAvailable(); 
	} 
	 
	@CliCommand(value = "jamon setup", help = "Setup Jamon into your project") 
	public void installJamon() { 
		operations.installJamon(); 
	} 
}

JamonCommands クラスに必要なのは、これだけです。このコードは jamon setup コマンドを公開するためにのみ必要なコードで、残りの作業はすべて JamonOperationsImpl クラスに委ねられます (リスト 12 を参照)

リスト 12. JamonOperationsImpl のコード
JamonOperationsImpl

JamonOperationsImpl need to implement two methods – \
isInstallJamonAvailable() and installJamon(). 

The isinstallJamonAvailable() method returns a boolean indicating whether 
command is available at this location or not. I want to enable JAMon only for the web
applications so we need to perform the check whether the project is 
a web application or not. To do that we will write the code as shown below 

	public boolean isInstallJamonAvailable() { 
		return projectOperations.isProjectAvailable() &&
        fileManager.exists(projectOperations.getPathResolver()
			.getIdentifier(Path.SRC_MAIN_WEBAPP, "/WEB-INF/web.xml")); 
	}

リスト 12 に記載したコードでは、ProjectOperations サービスを使用して、プロジェクトがこのロケーションで使用可能になっているかどうかをチェックし、web.xml ファイルのパスを取得します (web.xml ファイルは Web アプリケーションにのみ存在します)。ProjectOperations によって指定されたロケーションにweb.xml が存在するかどうかをチェックするには、FileManager サービスが使用されます。

実装しなければならない 2 つ目のメソッドは、installJamon() です。このメソッドで、JAMon 依存関係を pom.xml に追加し、Bean 定義を webmvc-config.xml に追加しなければなりません。メソッドのコードを作成する前に、src/main/resources/org/xebia/roo/addon/jamon フォルダー内に configuration.xml という名前の XML ファイルを作成する必要があります。フォルダー構造 (org/xebia/roo/addon/jamon) は、Roo アドオンのパッケージ構造と同じです。configuration.xml は、リスト 13 に示す JAMon バージョンと JAMon JAR 依存関係を定義します。

リスト 13. configuration.xml の内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<configuration> 
    <jamon> 
        <properties> 
            <jamon.version>2.4</jamon.version> 
        </properties> 
        <dependencies> 
            <dependency> 
            <groupId>com.jamonapi</groupId> 
            <artifactId>jamon</artifactId> 
            <version>${jamon.version}</version> 
        </dependency> 
        </dependencies> 
    </jamon> 
</configuration>

次は、依存関係を pom.xml に追加するためのコードを作成します (リスト 14 を参照)。

リスト 14. pom.xml に依存関係を追加するためのコード
	public void installJamon() { 
		Element configuration = XmlUtils.getConfiguration(getClass()); 
		updatePomProperties(configuration); 
		updateDependencies(configuration); 
	} 

	private void updatePomProperties(Element configuration) { 
		List<Element> properties = \
XmlUtils.findElements("/configuration/jamon/properties/*"
		, configuration); 
		for (Element property : properties) { 
			projectOperations.addProperty(new Property(property)); 
		} 
	} 

	private void updateDependencies(Element configuration) { 

		List<Dependency> dependencies = new ArrayList<Dependency>(); 
		List<Element> jamonDependencies = XmlUtils.findElements(
			"/configuration/jamon/dependencies/dependency", configuration); 
		for (Element dependencyElement : jamonDependencies) { 
			dependencies.add(new Dependency(dependencyElement)); 
		} 
		projectOperations.addDependencies(dependencies); 
	}

これは、pom.xml に依存関係を追加するための標準的なメカニズムであり、ほとんどの Roo アドオンでは、このメカニズムが使用されています。リスト 14 に記載したコードは、読めばその内容が明らかなように、Spring Roo ユーティリティー・クラス XmlUtils を使用して configuration.xml の内容を読み取り、それから ProjectOperations サービスを使用して pom.xml ファイルを更新します。

pom.xml 依存関係を追加した後は、web-jamon-config.xml という別の Spring 構成を作成する必要があります。ここに、JamonPerformanceMonitorInterceptor の Bean 定義を含めます。

リスト 15. web-jamon-config.xml の内容
<?xml version="1.0" encoding="UTF-8" standalone="no"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:mvc="http://www.springframework.org/schema/mvc" \
xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation=\
"http://www.springframework.org/schema/beans \
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd     
	http://www.springframework.org/schema/context \
http://www.springframework.org/schema/context/spring-context-3.0.xsd     
	http://www.springframework.org/schema/mvc \
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 


	<bean id="jamonPerformanceMonitorInterceptor" 
		class=\
"org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor"> 
		<property name="trackAllInvocations" value="true"></property> 
		<property name="useDynamicLogger" value="true"></property> 
	</bean> 

	<bean id="autoProxyCreator" 
		class=\
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
		<property name="interceptorNames"> 
			<list> 
				<idref bean="jamonPerformanceMonitorInterceptor" /> 
			</list> 
		</property> 
		<property name="beanNames"> 
			<list> 
				<value></value> 
			</list> 
		</property> 
	</bean> 

</beans>

リスト 15 に記載した web-jamon-config.xml ファイルには、Spring ベースのアプリケーションで JAMon に必要なあらゆるものを構成していますが、唯一指定していないのは、モニター対象とする Bean の名前です。コード・ジェネレーターがモニター対象の Bean を予測することはできないため、これを指定するのはアドオン開発者の仕事となります。

次に、この web-jamon-config.xml ファイルを webmvc-config.xml が常駐する WEB_INF/spring フォルダーにコピーするためのコードを作成し、webmvc-config.xml 内に、web-jamon-config.xml をインポートするための add import 文のコードを作成します (リスト 16 を参照)。

リスト 16. pom.xml を操作するコード
public void installJamon() { 
		 
	// update pom.xml code 
	PathResolver pathResolver =
        projectOperations.getProjectMetadata().getPathResolver(); 
	String resolvedSpringConfigPath = pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP,
        "/WEB-INF/spring"); 
	if (fileManager.exists(resolvedSpringConfigPath + "/web-jamon-config.xml")) { 
			return; 
	} 
	copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
		 
	String webMvcConfigPath = resolvedSpringConfigPath + "/webmvc-config.xml"; 

	new XmlTemplate(fileManager).update(webMvcConfigPath, new DomElementCallback() { 
		public boolean doWithElement(Document document, Element root) { 
			if (null ==
               XmlUtils.findFirstElement\
("/beans/import[@resource='web-jamon-config.xml']",
                   root)) { 
                   Element element = document.createElement("import"); 
		        element.setAttribute("resource", "web-jamon-config.xml"); 
				root.appendChild(element); 
		        return true; 
		    } 
		    return false; 
		   } 
	}); 
		 
} 
	 
private void copyTemplate(String templateFileName, String resolvedTargetDirectoryPath) { 
	
    try { 
	    FileCopyUtils.copy(TemplateUtils.getTemplate(getClass(),
               templateFileName), fileManager.createFile(
	            resolvedTargetDirectoryPath + "/" +
                   templateFileName).getOutputStream()); 
	} catch (IOException e) { 
           throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e); 
    } 
}

上記で使用している XmlTemplate クラスは、Spring Web フロー・アドオンにあります。したがって、この Web フロー・アドオンの依存関係をアドオンに追加しなければなりません (リスト 17 を参照)

リスト 17. Web フロー・アドオンの依存関係を追加する
	<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.web.flow</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

リスト 17 に示されている roo.version は、使用している Roo のバージョンです。

このアドオンで最後に必要な作業は、プロジェクトのロギングを構成して、トレースするログ・レベルを設定することです。それには、log4j アドオンの処理実行クラス、LoggingOperations を使用します。このクラスを使用するには、まず、pom.xml ファイルにロギング・アドオンの依存関係を追加する必要があります (リスト 18 を参照)。

リスト 18. ロギング・アドオンの依存関係を追加する XML コード
	<dependency> 
		<groupId>org.springframework.roo</groupId> 
		<artifactId>org.springframework.roo.addon.logging</artifactId> 
		<version>${roo.version}</version> 
      		<type>bundle</type> 
	</dependency>

この依存関係を pom.xml に追加したら、以下のコード行を使用して LoggingOperationJamonOperationsImpl クラスに追加します。

@Reference private LoggingOperations loggingOperations;

次に、以下の行を installJamon メソッドに追加します。

loggingOperations.configureLogging(LogLevel.TRACE, LoggerPackage.PROJECT);

このアドオン用に作成しなければならないコードは、これですべてです。リスト 19 に、JamonOperationsImpl クラスの完全なコードを記載します。

リスト 19. 完成した JamonOperationsImpl のコード
@Component 
@Service 
public class JamonOperationsImpl implements JamonOperations { 
       @Reference private FileManager fileManager; 
       @Reference private ProjectOperations projectOperations; 
       @Reference private LoggingOperations loggingOperations; 


       public boolean isInstallJamonAvailable() { 
               return projectOperations.isProjectAvailable() && 
fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(Path.SRC_MAIN_WEBAPP,"/WEB-INF/web.xml")); 
       } 


       public void installJamon() { 
               Element configuration = XmlUtils.getConfiguration(getClass()); 
               updatePomProperties(configuration); 
               updateDependencies(configuration); 
               PathResolver pathResolver = 
projectOperations.getProjectMetadata().getPathResolver(); 
               String resolvedSpringConfigPath = 
pathResolver.getIdentifier(Path.SRC_MAIN_WEBAPP, 
            "/WEB-INF/spring"); 
               if (fileManager.exists(resolvedSpringConfigPath 
+ "/web-jamon-config.xml")) { 
                       return; 
               } 


               copyTemplate("web-jamon-config.xml", resolvedSpringConfigPath); 
                
               String webMvcConfigPath = resolvedSpringConfigPath 
+ "/webmvc-config.xml";


               new XmlTemplate(fileManager).update(webMvcConfigPath, 
new DomElementCallback() { 
                       public boolean doWithElement(Document document, Element root) {
                            if (null == XmlUtils.findFirstElement(
"/beans/import[@resource='web-jamon-config.xml']",
root)) { 
                                 
Element element = document.createElement("import"); 
                                element.setAttribute("resource", "web-jamon-config.xml"); 
                                root.appendChild(element); 
                                return true; 
                             } 
                             return false; 
                       } 
               });
               loggingOperations.configureLogging(LogLevel.TRACE, 
LoggerPackage.PROJECT); 
       } 
        
       private void copyTemplate(String templateFileName, 
String resolvedTargetDirectoryPath) { 
               try { 
FileCopyUtils.copy(
      TemplateUtils.getTemplate(getClass(), templateFileName),
              fileManager.createFile(resolvedTargetDirectoryPath + "/" + 
              templateFileName).getOutputStream()); 
               } catch (IOException e) { 
                       throw new IllegalStateException(
               "Encountered an error during copying of resources for Jamon addon.", e);
               } 
       } 
        
       private void updatePomProperties(Element configuration) { 
               List<Element> properties = XmlUtils
     .findElements("/configuration/jamon/properties/*",configuration);
               for (Element property : properties) { 
                       projectOperations.addProperty(new Property(property));
               } 
       } 


       private void updateDependencies(Element configuration) { 
               List<Dependency> dependencies = new ArrayList<Dependency>(); 
               List<Element> jamonDependencies = XmlUtils.findElements(
           "/configuration/jamon/dependencies/dependency", configuration); 
               for (Element dependencyElement : jamonDependencies) { 
                       dependencies.add(new Dependency(dependencyElement)); 
               } 
               projectOperations.addDependencies(dependencies); 
       } 
        
}

このアドオンの完全なソース・コードは、Google Code リポジトリーからダウンロードすることができます。最後にいよいよ、作成したアドオンを使用してアプリケーションに JAMon サポートを追加します。

  1. Roo シェルを終了して、mvn clean install コマンドを実行します。ビルド・プロセスの実行中に、GPG パスフレーズの入力を求められます。
  2. Roo アドオンのビルドが完了したら、新しいコマンドラインを開き、jamon-client という名前のディレクトリーを作成します。ここに、アドオンの単純なクライアントを作成します。
  3. jamon-client ディレクトリーに移動し、roo コマンドを実行して Roo シェルを開きます。
  4. Roo シェルで、リスト 20 のコマンドを実行します。これにより、単純な Spring MVC Web アプリケーションが作成されます。
    リスト 20. 単純な MVC Web アプリケーションの作成
    project --topLevelPackage com.shekhar.roo.jamon.client --projectName jamon-client 
    persistence setup --provider HIBERNATE --database
    HYPERSONIC_IN_MEMORY
    entity --class ~.domain.MyUser
    field string --fieldName name --notNull
    controller all --package ~.web
  5. 以下の内容を入力して、アドオンをインストールします。
    osgi start --url <a
    href="../../../../">file:///</a><location \
    to addon target folder >
    /org.xebia.roo.addon.jamon-0.1.0.BUILD-SNAPSHOT.jar

    上記のコードによって、JAMon アドオンがインストールされて起動されます。アドオンのステータスを確認するには、osgi ps コマンドを使用します。

  6. jamon setup コマンドを入力すると、アプリケーションに構成された JAMon が表示されます。この時点で mvn tomcat:run コマンドによってアプリケーションを実行しても、コンソールにログは表示されません。それは、モニター対象の Bean をまだ構成していないからです。そこで、リスト 21 のコードに従って、web-jamon-config.xml に myUserController Bean を構成してみましょう。
    リスト 21. web-jamon-config.xml での myUserController の構成
    	<bean id="autoProxyCreator" 
    		class=\
    "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
    		<property name="interceptorNames"> 
    			<list> 
    				<idref bean="jamonPerformanceMonitorInterceptor" /> 
    			</list> 
    		</property> 
    		<property name="beanNames"> 
    			<list> 
    				<value>myUserController</value> 
    			</list> 
    		</property> 
    	</bean>
  7. mvn tomcat:run コマンドを使用してアプリケーションを実行すると、今度は Maven コンソールに JAMon ログが表示されるはずです。その一例をリスト 22 に記載します。
    リスト 22. JAMon ログの例
    TRACE MyUserController - JAMon performance statistics for method 
    [MyUserController.populateMyUsers]: 
    JAMon Label=MyUserController.populateMyUsers, Units=ms.: (LastValue=187.0, 
    Hits=1.0, Avg=187.0, Total=187.0, Min=187.0, Max=187.0, Active=0.0, Avg 
    Active=1.0, Max Active=1.0, First Access=Wed May 18 15:33:41 IST 2011, Last 
    Access=Wed May 18 15:33:41 IST 2011)

開発システムでアドオンが正常に機能していることをテストした後は、前に作成した Google Code プロジェクトにこのアドオンを送信します。アドオンを外部に公開するには、i18n アドオンを公開したときの手順に従ってください。同じく、アドオンを RooBot に登録するための手順も、i18n を登録したときの手順と同じです。


まとめ

この記事では、Spring Roo アドオン・アーキテクチャーの概要と、国際化対応アドオンおよびシンプル・アドオンを作成する方法を説明しました。このアドオン・アーキテクチャーが Roo にとって重要な理由は、このアーキテクチャーがもたらす柔軟性によって、Roo では新しい機能を素早く追加できるようになっているためです。開発者にとっては、このアーキテクチャーは、機能が世界のさまざまな言語および文化で実装されるのを待たなくても、それぞれの要件を満たすことができる重要なアーキテクチャーです。また、後になって機能が Roo に組み込まれた場合でも、このアーキテクチャーのおかげで比較的簡単に実装を変更してカスタム・ソリューションを削除することができます。

連載「Spring Roo 入門」の第 4 回では、高度なラッパー・アドオンを作成する方法について説明します。

参考文献

学ぶために

製品や技術を入手するために

議論するために

  • developerWorks blogs から developerWorks コミュニティーに加わってください。
  • developerWorks コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=762692
ArticleTitle=Spring Roo 入門: 第 3 回 Spring Roo のアドオンを開発する
publish-date=10072011