土曜日, 7月 25, 2009

【Google App Engine】 AJAX CRUDサンプルとJDO代替ライブラリ

RESTfulなWebサービスとワンソースマルチビュー

 先日行ったプレゼンの請求書DEMOでは、以下のように、HTMLの請求書を直接編集後、PDFを表示させるというところをお見せした。(以下のHTMLを表示させて右クリック、Searchで何かを選択してデータを読み込む、さらに右クリックでPDFを選択して生成)

 請求書デモ








 これは一見、統合されたアプリのように思えるかもしれないが、単なる疎結合なサービスの組み合わせであるにすぎない。つまり、JSONやXMLでCRUDできる機能だけが実装されたRESTfulなGAE上のサービスと、そのサービスに対してAJAXでアクセスするHTMLとJavaScript。そして、GAEのサービスからXMLを取得してPDFを生成するReflex iTextサービスの3つの組み合わせで成り立っているものである。特筆させていただきたいのは、ブラウザで表示させたHTMLとPDF生成で使ったテンプレートHTMLは全く同じものを使用しているという点。GAEのサービスから取得したものであるから、データはもちろん同じものである。このように、Reflexは、ブラウザやPDFなど様々なViewに対して、同じEntityを与えさえすれば、同じように表示させることができる。これをワンソース・マルチビューという。(そもそも、1つのEntityから複数の写像をとれるという意味で、名前をReflex(写像)としている)
 このように、ブラウザ以外にも、携帯やiPhone、Android、Flex2などの異なるメディアや端末に対象を広げられれば、コミュニケーションの幅を簡単に広げることができるため、ワンソース・マルチビューは今非常に重要視されている概念となっている。また、 Chrome OS戦略とIT世界の対立軸 でも述べているとおり、Googleは、RESTfulなWebサービスを基本とすることで、コミュニケーションに革命をもたらすとまでいいきっている。

Entityをそのまま表示させる

 これまで説明したように、Reflexではサーバで画面を作ることはしない。JSPも使わない。こうしてしまうと、どうしても密結合なアプリになってしまう。これは非常に大きなデメリットである。Reflexでは、JSONやXMLのCRUDだけが行えるサービスを基本とするが、JSPも使わないとなると具体的にどのようにブラウザで表示させればよいかが問題となる。この点について説明しよう。そんなに難しく考えないことがポイントである。

 まず、HTMLでモックを作り、表示させたいタグにIDを振る。画面が出来たら、IDを全部抽出して並べてルートタグで括る。これが表示用エンティティ。あとはそのエンティティをJavaでも実装して、AJAXを使って受け取れるようにする。JSONだとeval()できるので楽である。あとは、evalした個々のデータをHTMLのidに対してJavaScriptで挿入すればよい。具体的には、DEMOのinvoice.htmlとdisplay.jsを見ていただくのがよいと思う。ちなみに、Reflex iTextのデータ挿入もほぼ同じやりかたで行っている。また、高速化プロジェクト その1で述べたように、パフォーマンスも特に心配することはない。

 ただ、何でもかんでもこのスタイルがよいわけではないことも付け加えておく。SEO対策などで、サーバが出力する最初の段階から完全なHTMLでないとまずい場合などがあるからだ。そういう場合は、Reflex iTextのように、テンプレートとXMLから完全なHTMLを生成するようなサービスを介すとよいと思われる。いずれにしても、画面をベタ書きして疎結合を損なう設計になることだけは避けたいところである。

JDOとスケーラビリティ

 ここからが本当に言いたいところ。

 我々が検証した限り、JDOは大規模データを処理できないことがわかっている。正確には、JDOQLであるが、たった6千件のデータでさえ検索することができないのである。Indexが勝手に作成されてIndex爆発が起きる問題など、いくつか致命的なものもあるが、最も酷いのは、検索対象を絞るページングなどの範囲指定ができないことである。実は、JDOQLは5千件ぐらいまでは何とか検索できる。あれ?上限は千件までじゃなかったっけ?と不思議に思う方はGAEをよく知っている方。そう、一度にFetchできるのは千件までなのだが、それはDatastoreAPIの話。上位実装であるJDOではなんと5千件一括検索ができてしまうのだ。余計なことに、そんなことができる反面、6千件だともうフリーズしたように無反応になる。setRange()を指定してもダメ。getObjectById()やequalの検索条件を指定してやっと1件取得できるのみ。keyの複数件検索も未サポートなので、もう、これは使い物になりません。(※ただし、トランザクションや更新系はJDOのPMで問題なく使えている)
 そこで、私たちはJDOQLを諦め、低レベルのDatastoreAPIだけを使った検索ユーティリティを作成することにした。これを使えばPagingもできて大規模データの操作も問題ない。先の請求書DEMOも使用している。次回はこの中身について説明していきたいと思う。

<関連>
Reflex GAE
Entityとトランザクション
JDOから直接JSON、XML
AXIS2のデータバインディング能力
JDOから直接SOAP、ATOM。それからDeep Copy
Pagingをどうやって実現するか
RESTfulアプリのCRUDサンプル -Servlet編-

0 件のコメント:

コメントを投稿