Google App Engine for Java(GAE/J)上のGWTとRPC

今日もちょっとGAE/J(Google App Engine for Java)とGWT(Google Web Toolkit)の話。

ここ数日、Slim3やらドラッグアンドドロップやら、色々試してみましたが、

ちょっと原点に戻ろうかと思います。

Google製の「GWT」ですね。

Google Web Toolkitについて、グーグル様によれば…。

Google Web Toolkit

デベロッパーには生産性を、ユーザーにはパフォーマンスを

最新のウェブ アプリケーションの作成は、面倒でエラーの発生しやすいプロセスです。デベロッパーは 90% の時間をブラウザ固有の動作への対処に費やすことがあります。それに加えて、JavaScript の大規模なコード ベースや AJAX コンポーネントの作成、再利用、管理はもろくなりやすく、困難です。Google Web Toolkit(GWT)を使用すると、この難題が容易になります(Google Plugin for Eclipse を使用するとさらに便利です)。デベロッパーは Java プログラミング言語を使用して、複雑かつ高パフォーマンスの JavaScript フロントエンド アプリケーションをすばやく作成し、管理できるようになります。

Javaで書いて、そしてGWTのエンジンでそれをJavascriptというか、

AJAXなコードを生成してくれるものです。

要するに、リッチなクライアントのインタフェースを作ってくれる…のです。

そして、サーバー(GAE/Jの場合はJava)とクライアント(AJAX)の間に、

データをやり取りするためにいくつかの手段が用意されています。

Communicating with the server

・GWT RPC:Making Remote Procedure Calls (GWT RPC)
Javaのクラスをシリアライズ(直列化)して受け渡しをする

・JSON:Retrieving JSON Data via HTTP
JSONやXMLのデータをHTTPで受け渡す

・Cross-Site:Making Cross-Site Requests for JSONP
JSONP (JSON with padding)で受け渡す。

何れも悪くないのですが、ぉぅぇぃは「GWT RPC」が好きなんですね。

他の二つの方式は、結局テキストやスクリプトデータを受け渡ししていますが、

RPCの場合はオブジェクトそのものを受け渡しが出来ますので、

汎用性が高いし、オブジェクト指向的にも、

こっちのほうが色々強固なシステムを構築出来そうなんですね。

で、最近はこのパターンでちょっとハマっていましたので、

ちょっと簡単に感想や所見を述べたいと思います。

まず、GWT RPCはオブジェクトをシリアライズして受け渡しをしている…わけなんですが、

すべてのクラスをそれで受け渡せるワケではありません。

サーバー側は、要するにJVMが回っていますので、基本的に何でもOKで、

それといった制限がありません。

が、GWTで生成したクライアント側は、

「何から何まで」のライブラリを対応しているわけではありません。

つまり、クライアント側に処理出来ないクラスを渡しても、

クライアント側はうまく捌けない…のです。

従いまして、クライアント側に「処理出来無さそう」なクラスをアクセスしようとしたら、

GWTコンパイルの時、こんな感じのエラーが出ます。

No source code is available for type パッケージ.クラス; did you forget to inherit a required module?

エラーメッセージの通り、つまりこれらのクラスのためのコードが足りません…、

必要なモジュールを継承(?)してください…ということですね。

一般的に、ウェブサービス上のデータ(リクエスト?)の流れはこんな感じ…、

「クライアント(GWT)⇔サーバ(GAE)⇔データベース(Datastore)」。

GAEのほうは割りとフリーダムですが、GWTとDatastoreには制限があります、

同じグーグル様のパッケージなので、共通している…っと思いたいところですが、

困ったことに、GWTとDatastoreの制限は必ずしも一致していないのですね。

つまり、Datastoreには使えるのに、GWTには扱えない、

GWTには扱えるのに、Datastoreには扱えない…のようなケースがあります。

例えば、Datastoreのほうには、GAEのために用意されたUserクラスを保存出来ますが、
(*com.google.appengine.api.users.User)

デフォルトのGWTはそれを対応していませんので、

UserのインスタンスをRPCでGWT側に送ろうとしたら、エラーが出ます。

この問題に対して、無理やりGWTをDatastoreにあわせる…、

両方同時に扱えるクラスしか使わないようにする方法もありますが、

いろいろ制限が多いのですね。

その他、その差異をサーバー(GAE)に吸収させる方法もあると思われます。

つまり、保存するためにRPCでGWTから送られたオブジェクトを

そのままDatastoreに入れるではなく、

何かしらのクラスやデータの変換を行ってから永続化(格納)する。

同じくDatastoreから取り出したデータオブジェクトも、

そのままGWTに送るではなく、何かしらの変換を行ってからクライアントへ…ですね。

もしGWTのほうに色々なクラスを扱いたいのであれば、

それをGWTの設定ファイルである◯◯.gwt.xmlの中に記述する必要があります。

例えばこんな感じ

<inherits name=’com.google.gwt.user.User’ /<

この「com.google.gwt.user.User」というのは、

GWT SDKの「gwt-user.jar」の中のパッケージを辿っていけば、

「User.gwt.xml」ってファイルを確認することが出来ます。

まあ、さらに色々継承している…って感じだけどね。

ちなみにこんな感じです。

↓User.gwt.xmlの中身

User.gwt.xmlの中身

つまり、だ、基本的にサポートされているクラスなら良いのですが、

そうではないモノならば、モジュールを入れたり、

無かったら自分でモジュールを作ったり、いろいろやらないと、

クライアント側には扱えない…ということですね。

で、このモジュールの扱い方について、色々試しましたら、

少しずつ分かってきた…のような気がしますが、

もうちょっと調べないと行けませんので、

更に詳しく成ったら、何かしらの記事を書きたいと思います。

ちなみにGWTのプロジェクトはデフォルトに、

client、server、sharedの三つのパッケージがあります。

クライアント関連のものはclient(設定すればsharedも)パッケージの中に入れるようにしたい。

GWTの制限を受けずに色々処理させたいなら、

それをサーバー側に定義し、serverパッケージの中に入れといたほうが、

色々分かりやすい…のような気がします。

意識せずに適当にやったら、色々とエラーに悩まされてしまいますね。

ちなみにどのパスをGWTのコンパイルに含むかどうかは、

自分のプロジェクトにある「*.gwt.xml」の中の「source path」で設定できます。

GAE/Jにしても、GWTにしても、チュートリアルに沿ってやったら、

そのお気楽さとパフォーマンスに感動するばかりですが、

お気楽モードでいじりまわすと、あっちこっち引っかかってしまいますね。

う〜む、まずは正しい理解、これ大事ですね。

やっぱり真面目に勉強しないと!

また色々触っていきます。

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*