スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

Android/GAE Hack-a-thonに参加したメモ

Android/GAE Hack-a-thonに参加してきました。Android使いとApp Engine使いが集まり役割分担してなんか作るという面白イベントです。私はAndroid全然しらなくて対応携帯も持っていませんが、この機会に勉強したいなぁ〜と参加してみました(余談:携帯+サーバーでコラボレーションとか昔から好きで、iアプリが出た時は「これはコラボツールだ!」と興奮してすぐさまチャットクライアントを書いて、WebLogicサーバー間でEJBに分散オブジェクト通信させるcometサーバー書いたりしましたよ〜)。

今回の参加者は全部で15人くらい? App Engineな人は@shin1ogawaさんとか毛利さん、私など4〜5人でした。まずは松尾さんが画像、テキスト、Geo、センサ、チュートリアルというテーマを決めます。各人は自分の参加したいグループに分かれてアイディアソン開始。私はGeoを選び、@itogさん、@bols_blueさんというAndroidな方々と3人でチームを作りました。

Ashiatoアプリを作るのだ

Geoチームは、@itogさんが練られてきたアイディアを元に「Ashiato」アプリを作ることにしました。Android携帯でGPS情報を取得して、App Engineに記録していき、それをお友だち同士で共有する、みたいな足跡共有サービスみたいなものです。例えば複数のクルマでスキーとか行くときに、先に行った友達の足跡をたどってく…といった使い方を想定してます。

まずはGoogle Wave上で共有のwave(ドキュメント)を作って、私はサーバーの仕様を以下のように決めました。

URL 
    http://hackathon-ashiato.appspot.com/

/ashi/put
機能
    指定したユーザーの足跡を追加する
パラメータ
    * email:追加したいユーザーのメールアドレス
    * lat
    * lng
例
    * http://hackathon-ashiato.appspot.com/ashi/put?email=foo@example.co.jp&lat=0.123&lng=0.123
戻り値の例
    OK 

/ashi/get
機能
    * 指定したユーザーの最新の足跡データ一覧をJSONで返す(createdAtの降順)
パラメータ
    * email:取得したいユーザーのメールアドレス
    * limit(省略可):取得する足跡データの件数(省略時は1)
例
    * http://hackathon-ashiato.appspot.com/ashi/get?email=foo@example.co.jp
戻り値の例
    * 登録データがある場合は、最新1件を返す
[{
    "createdAt":1261200543809,
    "email":"foo@example.co.jp",
    "key":{"complete":true,"id":1,"kind":"Loc","name":null,"parent":null},
    "point":{"latitude":0.123,"longitude":0.123}
}]
    * 未登録の場合は、空リストを返す
[]

これだけなので、サーバー側は位置情報を保持する「Loc」というカインドを1つ作ってそれを読み書きするという簡単なロジックを実装するだけです。こうした傾向は他のチームでも同様だったようで、Androidのようなリッチクライアントだとサーバー側が持つべきロジックは少なくなるなあという印象です。

なお今回皆で書いたコードは、hackathon-jpのSVNリポジトリで公開してます。

ところで今回はユーザー認証とかすっとばしてます。Android携帯からApp Engineがリクエストを受けたとき、そのユーザーのGoogleアカウント情報も取得できたら嬉しいな…と思いましたが、現状ではできないことを皆さんに教えていただきました。これできたら便利だなぁ〜。。

Slim3 Datastore触ってみた

私は今回、Slim3 Datastoreを初めて触ってみました。まずはslim3-blankを使ってプロジェクトの土台を用意したのち、Locという位置情報用のカインドを作って@modelアノテーション付けて、あとはベタにputするサーブレットgetするサーブレットを書きました。

例えば位置情報をputする部分では、

        final Loc loc = new Loc();
        loc.setEmail(email);
        loc.setPoint(new GeoPt(Float.parseFloat(lat), Float.parseFloat(lng)));
        loc.setCreatedAt(new Date());

って書いて保存したいLocオブジェクトを作ったら、Slim3 DatastoreのAPIを使って

        Transaction tx = Datastore.beginTransaction();
        Datastore.put(loc);
        Datastore.commit(tx);

って書くだけで保存されます。

クエリも超お手軽です。まずは、

        final LocMeta lm = new LocMeta();

って感じでLocMetaオブジェクトを取得します。これはLocクラスに@Modelアノテーションを付けとくと自動生成されるメタデータクラスで、これを使い、

        final List<Loc> locs =
            Datastore.query(lm).filter(lm.email.equal(email)).sort(
                lm.createdAt.desc).limit(limit).asList();

みたいなクエリを書けます。ああ簡潔かつ美しい!

  • JDOではこれと同じことをするのに数行書いてたけどSlim3だと1行で書ける
  • JDOでは検索結果リストをcastする必要があるけど、Slim3だとジェネリックス対応しててListにさくっと入る
  • JDOではJDOQLとか書いてたけど、Slim3ではクエリ全体をJavaのメソッド呼び出しやフィールド参照として書けるのでタイプセーフ。つまりQL文法ミスによる実行時エラーとか起きない
  • かつEclipseによるコード補完をフルに生かせる。上記例だと「lm.email.」まで書くとフィルタ条件一覧等がリストアップされるので、「equal」をそこから選んで…とか
  • このように使いやすくてかつJDOの3倍速い(赤い角が付いているようです)

そんな感じでSlim3 Datastoreを使ったおかげでサーバー側は手早く実装できました。

Google Maps API for FlashWebブラウザ画面もつくってみた

私のサーバー側作業は4時頃には終わったので、残り1時間でがんばって「足跡をGoogle Maps上に表示するWebブラウザインタフェース」をGoogle Maps API for Flashで作ってみました。このAPIではFlexコンポーネントとしてmapコンポーネントが提供されており、それを貼り付けるだけで自分のFlexアプリケーションにGoogle Maps地図を表示できます。

    <maps:Map xmlns:maps="com.google.maps.*" id="map" mapevent_mapready="onMapReady(event)" width="100%" height="100%" 
        key="Mapsのキー"/>

あとはサーバー側からJSONで送られてくる位置情報をもとにマーカーを打っていきます。

                var locs:Array = JSON.decode(result);
                for each (var loc:Object in locs) {
                    var ll:LatLng = new LatLng(loc.point.latitude, loc.point.longitude);
                    var markerA:Marker = new Marker(ll, 
                        new MarkerOptions({
                            strokeStyle: new StrokeStyle({color: 0x000000}),
                            fillStyle: new FillStyle({color: 0xff0000, alpha: 0.8}),
                            radius: 12,
                            hasShadow: true
                        }));
                    map.addOverlay(markerA);
                }

また、足跡表示したいひとのidを入力するとサーバーにgetリクエストするコードを書いておきます。実行結果はこんな感じ:

なんとか午後5時の発表には間に合いました。

ちなみに、このAshiatoサーバーは以下URLで動いてますので、上記仕様でご自由にお使いいただいて構いません:

http://hackathon-ashiato.appspot.com/

それと上記Flexページのソースはこちらです:

http://hackathon-ashiato.appspot.com/bin-release/srcview/index.html

ハッカソン荒らし登場

最後に各チームがそれぞれの成果を発表しました。残念ながらGeoチームはAndroid携帯上でのマップ表示UIの仕上げが間に合わなかったのですが、しかし上記例のように携帯からGPS情報を取得してサーバーに記録、Webブラウザに表示といったひととおりの機能は実装できました。嬉しい〜。

そして多数決で優勝チームを決めるのですが、毛利さんが参加されたセンサチームがAndroid Warsというすばらしい対戦ゲームを作り上げてて圧倒的投票数を獲得して優勝してました。毛利さんはChrome Extensionに引き続き2回目の優勝で、もはやハッカソン荒らし…恐ろしい子…という感じです。もう他のハッカソンには参加させてもらえないのではないかと心配です。本人にコツを聞いてみたところ事前の仕込みが重要らしいですwww

というわけで、Android+App Engineて面白いなぁ〜Slim3便利だなぁという実感を得た楽しいハッカソンでした。