GroovyコードをGAE/J上のTextareaに投入するとその場でAJAX実行できるGroovy web Consoleという妙に完成度の高い代物がある訳ですが、さーてBigTable叩いてみようかーと意気込んでJDOとかのAPIを呼び出そうとするとそんなクラスねえというエラーになります。これは、そのために必要なjarが同梱されてデプロイされてないからです。上のデモサイトでglaforge氏がそうしてないのは、BigTableを書き込みされたら困るからかな。
んで、そんなことは自分のアプリでやるなら何の問題もない。そのやり方:
(1)Groovy web Consoleのコードをgithubからとってくる。gitでとってくるもよし、単にダウンロードして展開するのでも良いです。
(2)war/WEB-INF/libに、JDO/JPA関係のそれらしきjarをぶっこむ。Guestbookのデモを参考に以下のようなものを入れときました。
datanucleus-appengine-1.0.0.final.jar datanucleus-core-1.1.0.jar datanucleus-jpa-1.1.0.jar geronimo-jpa_3.0_spec-1.1.1.jar geronimo-jta_1.1_spec-1.1.1.jar groovy-all-1.6.1.jar jdo2-api-2.3-SNAPSHOT.jar
(3)同様に、Guestbookのデモからwar/WEB-INF/classes/META-INF/jdoconfig.xml をコピってくる。
(4)appcfg update warする。その前に、war/WEB-INF/appengine-web.xmlのapplicationを書き換えとこう。さもないとglaforge氏のアプリを書き換えにいくよ!
これでGAEのJDOなりJPAのサンプルが、WEB上からGroovyを直接入力して試せますことです。ためしてないけどURL fetchもmailもいけると思う。わっはっは。この方式の偉大なところはいちいちアプリをコンパイルしたりアップロードしたりしないで良いところ。Groovyは現状ローカル環境では動かない*1ので有用であるというだけでなく、純粋にJavaを使いたい人にとっても、ローカルと本番環境の違いもあるわけでして、APIの動作を調査したりするにはJavaで試行錯誤するのよりも簡単だと思うよ。
といいつつまだPersistanceManagerがとれるところまでしか確認してない。アノテーションつきのjdoクラス定義がGAE上でオンザフライでenhanceされるんだろうか・・。それはできないかもわからんね・・。低レベルAPIやクエリは問題ないと思うけど。続きはまた。
PS: datastore overviewにあるPMFクラス相当なものはGroovy側ではなくJavaであらかじめ書いとく必要がありますね。PersistanceManagerを使い回すのにMemcacheに入れとけば何とかなるかと思ったら、シリアライズ不可なのでできないみたい。
PPS: Groovyで書かれたJDOクラスのサーバ側でのenhancementはできませんでした(予想通りと言えば予想通り)。Grails 1.1.1ではGroovyのJDOクラス定義ができてるんですが、enhancementはデプロイ時にローカル側でやってるってことですね。当然そうすべきではあります。classファイルを加工(enhancement)したものを保存するって話だからね。
PPPS: ぬおー。デプロイ時にindexがないと結局クエリができないのか。動的に発行される新たなクエリに対応するindexを作るというわけにはいかないのだろうな。
PPPPS: indexの問題については、「datastore-indexes.xml」というファイルをwar/WEB-INF直下におくことで回避。これはGrailsのやり方を参考にしました。
<?xml version="1.0" encoding="utf-8"?> <datastore-indexes xmlns="http://appengine.google.com/ns/datastore-indexes/1.0" autoGenerate="true"> </datastore-indexes>
現状、java.util.Dateの永続化がうまく行ってないなどいくつか問題はあるものの、以下のような感じでごく基本的にはGroovy Web ConsoleからJDOクエリが一応呼び出せました。
import org.jggug.*; import javax.jdo.*; def pm = PMF.get().getPersistenceManager(); // PMFはJavaで書いておく Query query = pm.newQuery(Employee.class); query.setFilter("firstName == firstNameParam"); query.declareParameters("String firstNameParam"); List<Employee> results = (List<Employee>) query.execute("hoge"); results.each { println it.firstName }
*1:これは、オンザフライでサーバサイドでgroovyをランタイムコンパイルしたい場合の話。groovycするなら、ローカルでも何の問題もない。