連載「Java
開発 2.0」では、これまで数回にわたって単純なクラウド用モバイル・アプリケーションをベースに話を進めてきました。Magnus
と名付けたこのアプリケーションは、モバイル機器の位置情報をリッスンする HTTP エンドポイントの役割を果たします。Magnus
が機能するためには、特定の時点でのアカウントの位置を示す JSON 文書が含まれる HTTP PUT
リクエストを受信しなければなりません。この Magnus を開発し、拡張するために今まで使ってきた Web フレームワークは、Play です (「参考文献」を参照)。
Play は、MVC スタックを提供するという点で Grails とよく似ています。Play ではビュー (JSP、GSP、テンプレートなど) を使用するコントローラー (サーブレット) を簡単に定義して、何らかの方法でモデルを操作することができます。これらのモデルを実装するには、Hibernate、JPA、あるいはその他の巧妙な ORM 風の技術で強化した POJO (Plain Old Java Object) を使用します。
MVC は以前からの標準ですが、Grails や Play のようなフレームワークの登場によって、大幅に変化しています。かつて、Web でのリクエストとレスポンスによる単純な対話を (例えば Struts を使用して) できるようにするために必要だった作業量を思い出してください。それだけでも、MVC Web アプリケーションをいかに短時間で構築できるようになったか実感するはずです。そうは言っても、すべての Web アプリケーションで MVC インフラストラクチャーが機能していなければならないわけではありません。最近では、MVC スタックがまったく必要ない Web アプリケーションもあります。
このような異端の意見に抗議してブラウザーを閉じる前に、Magnus を思い出してください。Magnus はあくまでもデモ用に考案されたものですが、このクラウド用モバイル・アプリケーションには従来のビュー・コンポーネントは一切含まれていません。その大部分は、すでに成功を収めている実在のサービスを手本にしています。例えば Twitter や Foursquare のように、Magnus は世界中のさまざまな機器からのメッセージを受信します。大まかに言うと、Magnus は Web サービスです。すべての Web サービスがその役目を果たすために MVC スタックを必要とするわけではありません。場合によっては、Web スタックがなくても、超軽量 Web フレームワークで必要を満たせるものもあります。
今月は、このような超軽量 Web フレームワークの 1 つである Gretty を見て行きます。この迅速な開発が可能なフレームワークはごく最近登場したばかりで、専用のホーム・ページもないほどですが、そもそもホーム・ページは必要ないかもしれません。Gretty が受け継いでいる系統 (Netty) と関連性 (Groovy) だけで、Gretty を Java 2.0 Web 開発ファミリーの一員と見なすにはすでに十分だからです。Gretty は多くの開発者がまだ気付いてもいない必要性を満たします。(それは、真の Web 2.0 スタイルです。ご存知でしたか?) Gretty は本番環境で使用するのにも十分安定しています。ただし、さまざまな環境がまだ十分には整っていないのを承知で使用する気があれば、の話です。
大量のコードやそれに伴う JAR ファイルもなしに、単純なサーブレットだけで Web サービスを構築できるという新しい「軽量」のパラダイムに対して、Servlets API が初めて登場した頃のことを覚えている開発者が懐疑的な態度をとるのは無理もありません。例えば、Restlet および Jersey といった Web サービス・フレーワークは、開発を迅速化する手法として他とは少し異なる手法を取っていて、クラス継承、アノテーション、さらには標準 JSR をベースに RESTful な Web サービスを作成します。シナリオによっては、この 2 つは今でも優れた選択肢となります。
けれども、(かつての軽量フレームワークではなく) 新しい軽量フレームワークのいくつかは、Web サービス、あるいは単純な HTTP エンドポイント (「ルート」とも呼ばれます) を驚くほど簡単に定義できることが明らかになっています。その単純さは、サーブレットさえも上回るほどです!
当初、これらの新しい軽量フレームワークは、Ruby 用の Sinatra や Node.js 用の Express をはじめ、Java 以外のプラットフォームで登場しましたが、Java プラットフォーム用の興味深いプロジェクトも登場し始めました。そのなかの 1 つが Gretty で、もちろん Groovy と JVM 向けに作成されたものです。
Gretty には、私好みの点が少なくとも 2 つあります。その 1 つは、Groovy の Grape (後で詳しく説明します) を使用して依存関係を管理しやすくしているところで、もう 1 つは、単純な DSL のような構文でエンドポイントを定義できるところです。Gretty では、実際のビジネス・ロジックを処理する実用的な Web ルーティング・フレームワークをあっという間に (2、3 行の短いコードで) 定義してデプロイすることができます。一例として、リスト 1 に標準的な Hello World アプリケーションを素早く作成してみます。
リスト 1. Hello, World: これが Gretty です!
import org.mbte.gretty.httpserver.*
@GrabResolver(name='gretty',
root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local')
@Grab('org.mbte.groovypp:gretty:0.4.279')
GrettyServer server = []
server.groovy = [
localAddress: new InetSocketAddress("localhost", 8080),
defaultHandler: {
response.redirect "/"
},
"/:name": {
get {
response.text = "Hello ${request.parameters['name']}"
}
}
]
server.start()
|
リスト 1 では、ポート 8080 をリッスンするサーバーを作成した後、単純なルート・エンドポイントをセットアップして、そこに
nameパラメーターを含めています。他のエンドポイントに対するリクエストは、defaultHandler によって /
に戻されます。このデフォルト・ハンドラーは基本的に、リクエスト側クライアントに / の位置と併せて HTTP
301「moved permanently」コードを送信します。すべてのリクエストが受信する (コンテンツ・タイプが text/plain に設定された)
レスポンスには、「Hello」および渡されたパラメーターの値からなるストリングが含まれます。例えばパラメーターの値が「/Andy」だとすると、「Hello Andy」というストリングになります。
リスト 1
の興味深いところは、何よりもまず、アプリケーションに必要なのはこのリストで目にする内容だけだということです。構成ファイルもなければ、(Groovy 1.8 を除けば)
直接ダウンロードまたはインストールしなければならないものもありません。このサンプル・アプリケーションは、groovy server.groovy と入力するだけで起動することができます。
単純なテキストによるレスポンスではなく、多少高度なレスポンスにしたい場合はどうでしょう?その場合、Gretty にはいくつもの方法があり、そのうちの 2 つはかなり簡単な方法です。その 1 つは、リスト 2 で行っているように、レスポンス・タイプを HTML に設定することです。
リスト 2. Gretty での HTML レスポンス
"/:name": {
get {
response.html = "Hello ${request.parameters['name']}"
}
}
|
この場合、レスポンスのコンテンツ・タイプは text/html に設定されます。もう 1 つの方法として、Gretty では静的テンプレートと動的テンプレートを使用できるようになっています。例えば、単純な JSP/GSP 風の構造を使用してテンプレートを定義することができます (リスト 3 を参照)。
リスト 3. Gretty での HTML テンプレート
<html>
<head>
<title>Hello!</title>
</head>
<body>
<p>${message}</p>
</body>
</html>
|
これで、レスポンスの本体でこのテンプレートを参照することができます。
リスト 4. Gretty での Groovy++ テンプレート
"/:name" {
get {
response.html = template("index.gpptl",
[message: "Hello ${request.parameters['name']}"])
}
}
|
Gretty による迅速な開発の素晴らしさには、その一部に Grape (「参考文献」を参照)
が貢献しています。Gretty は Grape を使用してバイナリー依存関係、すなわち JAR ファイルを自動的にダウンロードします。すべてのファイルは、Maven
スタイルの推移的依存関係によってロードされます。そのため、リスト 1 ではアノテーション @Grab('org.mbte.groovypp:gretty:0.4.279') を入力するだけで、Gretty
の依存関係と合わせて、Gretty に関連付けられた JAR ファイルを取得することができました。アノテーション @GrabResolver(name='gretty', root='http://groovypp.artifactoryonline.com/groovypp/libs-releases-local') では、Grape が必要なファイルを見つけられる場所を示しています。
Grape は単純そうに見えますが、だからと言って本番環境に適していないということはありません。実のところ、Grape による必要な依存関係の自動ダウンロード機能は、Maven の同様の機能と何の違いもありません。Mavenは必要な依存関係をビルド時にダウンロードしますが、Grape はアプリケーションを初めて実行するときに、そのアプリケーションの実行中に依存関係をダウンロードするというだけです。Grape が必要な依存関係をローカルで検出できる場合、ダウンロードは必要ありません。必要な JAR は自動的にアプリケーションのクラスパスに配置されます。そのため、パフォーマンスが犠牲になるのは、Grape で構成したアプリケーションを最初に実行するときだけです。もちろん、指定された依存関係の必要とするバージョンを変更した場合にも、パフォーマンスに多少の影響があります。
これまでの説明で、Gretty の単純さは理解してもらえたと思います。この単純さは、開発時間の大幅な短縮をいとも簡単に実現するだけではありません。Gretty (あるいは同様のフレームワーク) は、Magnus のようなアプリケーション (データをリッスンする HTTP エンドポイント) にも申し分なく適しています。そこでこれから、Play や Grails といったかなり軽量なフレームワークを、Gretty で作成したさらに軽量なアプリケーションでまるごと置き換えるとどうなるのかを見てみましょう。
この Magnus の改造バージョンには、Morphia と MongoHQを使用します。記憶にあるかもしれませんが、この 2 つは Amazon Elastic Beanstalk を紹介する記事でも使用しました。Groovy の Grape ユーティリティーを新しい構成で使用するには、リスト 5 に記載するアノテーションをサーバーに追加する必要があります。
リスト 5. Morphia およびその依存関係の追加
@GrabResolver(name='morphia', root='http://morphia.googlecode.com/svn/mavenrepo/') @Grab(group='com.google.code.morphia', artifactId='morphia', module="morphia", version='0.99') |
今回使用する Morphia のクラスは、これまでの Magnus 改造バージョンでも使用してきたAccount と
Location です。つまり、この Gretty
によるエンドポイントでは、指定されたアカウントの位置情報の更新のみを行います。Morphia のクライアントは Gretty によるエンドポイントに JSON
文書を送信することになるため、Jackson も使用します。Jackson は、Gretty 内部にすでに組み込まれている、優れた JSON 処理フレームワークです。Grape が推移的依存関係を処理してくれるので、受信される JSON 文書を構文解析して単純な Java Map に変換するために必要なすべてのものにアクセスすることができます。
リスト 6. Gretty での位置情報の更新
def server = new GrettyServer().localAddress(new InetSocketAddress("localhost", 8080)).
"/location/:account" {
put {
def jacksonMapper = new ObjectMapper()
def json = jacksonMapper.readValue(request.contentText, Map.class)
def formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm")
def dt = formatter.parse(json['timestamp'])
def res = [:]
try{
new Location(request.parameters['account'], dt, json['latitude'].doubleValue() ,
json['longitude'].doubleValue() ).save()
res['status'] = 'success'
}catch(exp){
res['status'] = "error ${exp.message}"
}
response.json = jacksonMapper.writeValueAsString(res)
}
}
server.start ()
|
リスト 6 を見るとわかるように、受信される JSON 文書の Map
(json という名前を付けてあります) が作成されます。それに応じて、リスト 7 に示された Location クラスによって、位置情報が MongoDB に挿入されるというわけです。
リスト 7. 位置情報文書の作成 — Gretty バージョン
import com.google.code.morphia.annotations.Entity
@Entity(value = "locations", noClassnameStored = true)
class Location extends AbstractModel {
String accountId
double latitude
double longitude
Date timestamp
public Location(String accountId, Date timestamp, double lat, double lon) {
this.accountId = accountId
this.timestamp = timestamp
this.latitude = lat
this.longitude = lon
}
}
|
その上、この Location にはリスト 8 に示す Groovy スーパークラスがあります。
リスト 8. Location の基底クラス
import com.google.code.morphia.Morphia
import com.google.code.morphia.annotations.Id
import com.mongodb.Mongo
import org.bson.types.ObjectId
abstract class AbstractModel {
@Id
private ObjectId id;
def save() throws Exception {
def mongo = new Mongo("fame.mongohq.com", 32422)
def datastore = new Morphia().createDatastore(mongo, "xxxx",
"xxxx", "xxxx".toCharArray())
datastore.save(this)
return this.id
}
}
|
読者の中には、リスト 7 のコードに見覚えがある方がいらっしゃるかもしれません。この今回の Gretty 実装で、「Elastic
Beanstalk という伸縮自在な豆の木に登る」のリスト 3 に対して行った主な変更は、実際のファイル名を Location.java から Location.groovy
にするといったことぐらいなので、サーバーを起動する前にファイルをコンパイルする必要がありません。また、基底クラスも追加しました。位置情報は、URI
から取得した受信パラメーター account によってアカウントに結び付けられます。
成功を示すレスポンスは JSON で送信されます。エラーが発生した場合には、別のレスポンスが生成されることになります。
Gretty は可能な限り軽量になっています。ORM フレームワークは組み込まれていません。単純なテンプレートを別とすれば、堅牢なビュー・フレーワークもありません。しかし、他のフレームワークを組み込むことは可能です。こうした点は、Gretty を日常的に使用するのは時期尚早だということを意味するのでしょうか?テスト・フレームワークがないということも同様のことを意味するのでしょうか?その答えは「ノー」です。第一に、Gretty は Netty の評判の高いコードから作成されているので、当初からある程度は保証されています。そして第二に、自動テストであるかどうかに関わらず、他のあらゆる Web エンドポイントと同じように、Gretty をテストすることができます。実際、Gretty のテスト方法を確かめるには、そのソース・コードを見てください。ソース・コードにはテストが溢れていることがわかるはずです。
すべてのスタックが必要ではないこともあるからこそ、Gretty は、最近のフルスタックの Web フレームワークとはまったく逆の立場をとっています。Gretty のようなフレームワークを使うと必要な作業の量が増えすぎると思ったら、十分なドキュメントがある数多くのフルスタックの Java Web フレームワークのいずれかを使用したほうが楽かもしれません。それと同じく、Web サービス・リクエストおよびレスポンスを処理するのにスタック全体が必要であるかどうか疑問に思ったら、Gretty だけで十分に必要を満たせるかもしれません。
学ぶために
- 「Groovy++ in action:
Gretty/GridGain/REST/Websockets」(Alex Tkachman 著、DZone、2011年5月): これまで Gretty を話題にした出版物は、ごく少ししかありません。この紹介記事に、記事の著者が Groovy++ で実装したいくつかのサンプル・アプリケーションが記載されています。
- 連載「Java
開発 2.0」: この dW の連載では Java 開発の様相を塗り替える技術を詳しく探っています。今まで取り上げた話題には、Amazon
Elastic Beanstalk (2011年2月)、Java
開発者のための JavaScript (2011年4月)、MongoDB
(2010年9月)、NoSQL (2010年5月) などがあります。
- Grape
ユーザー・ガイド: Grape に興味がありますか?この Codehaus によるユーザー・ガイドでその概要を理解してください。
- Netty
のホーム・ページ: この Java NIO クライアント・サーバー・ソケット・フレームワークについて学んでください。
- 「Getting started with
new I/O (NIO)」(Greg Travis 著、developerWorks、2003年7月): この実践的チュートリアルでは、NIO ライブラリーのバッファーおよびチャネル、非同期 I/O、ダイレクト・バッファーなどを説明しています。
- ナレッジ・パス「Cloud
computing fundamentals」(2011年3月): クラウド・コンピューティングの概念、および IaaS、PaaS、SaaS という 3 つのサービス・モデルについて解説しています。
- 連載「多忙な
Java 開発者のための Scala ガイド」(Ted Neward 著、2008から2009年): Ted Neward が Scala プログラミング言語について掘り下げるこの連載では、単刀直入にこの言語機能の実際を検討しています。
- JJava Technology
bookstore で、この記事で取り上げた技術やその他の技術に関する本を探してください。
- developerWorks Java technology ゾーン: Java プログラミングのあらゆる側面を網羅した記事が豊富に用意されています。
製品や技術を入手するために
- Play フレームワーク: 開発者の生産性を重点に、RESTful なアーキテクチャーをターゲットとするフレームワークです。
- Gretty: Groovy 1.8.0 を入手するだけで、使い始めることができます。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2、Lotus、Rational、Tivoli、および WebSphere などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- developerWorks
コミュニティーに参加してください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者が主導するブログ、フォーラム、グループ、ウィキを調べることができます。

Andrew Glover は、ビヘイビア駆動開発、継続的インテグレーション、アジャイル・ソフトウェア開発に情熱を持つ開発者であるとともに、著者、講演者、起業家でもあります。また、easyb BDD (Behavior-Driven Development) フレームワークの創始者、そして『継続的インテグレーション入門 開発プロセスを自動化する47の作法』、『Groovy in Action』、『Java Testing Patterns』の 3 冊の本の共著者でもあります。詳細は彼のブログにアクセスするか、Twitter で彼をフォローしてください。