こんなサービスをつくってみた

いきなりですが、PayPalを使ったサービスを思いつきました。
PayPalって何?という方はこちらを見てみてください。
http://r.nanapi.jp/702/
主にインターネットショッピングでの決済に使われる事が多いようです。

イデア

思いついたのはこんなサービスです。

リアルで会っているのに、わざわざPayPalで決済するサービスです(キリッ

上の絵で、
青い人=お金を受け取る人
赤い人=お金を払う人
です。


青い人が、自分のPayPal IDと、もらいたい金額を入力し、
赤い人がQRコードリーダーで読み取ると、PayPalのボタンが表示されます。
PayPalボタンを押すと、PayPalのサイト上で承認を求められますので
承認すると、支払い完了です。

という訳で、

こちらがそのデモサイトです。
http://goo.gl/lEhuf

マーチャントIDには、P36WPNDPPYHSA を指定してみてください。
飛ばされるPayPalサイトはテスト環境ですので、以下の情報でログインもできます。

  • ID:buyer_1289487333_per@gmail.com
  • パスワード:buyerpass

ログイン後、「承認」しても大丈夫です。

用途

直接会ってるなら現金でいいじゃんというごもっともな突っ込みを頂きました。ので、自分の思う使い道をいくつか。
例えば、

  • 大人数の勉強会、イベントの代金をQRコードをスクリーンに写して集金
  • 個人間でカード払い(PayPal自体の機能なのでこのサービスなしでもできますが、より簡単に)

......もっと考えます(笑)

注意点

  • もちろん数%の手数料が掛かりますので、それはどちらかが負担することになります。
  • 日本国内では、PayPalを使った個人間の「送金」は法律で禁止されているそうですので、何らかの物品、サービスに対しての対価としてご利用頂く前提になります。

参考URL
http://twitter.com/#!/paypaljapan/status/28003273121

Mashup Award 6に応募しました!

ご存知の方も多いと思いますが現在Mashup Award 6が開催されていて、
ちょうどAppEngineとChrome拡張を使ったアイデアを思いついたので作って応募しました。
http://ma6works.mashupaward.jp/oubo/342/

PinIt(ぴんいっと)といいます。

https://chrome.google.com/extensions/detail/fmkklenggkaimfbahdenjjibgihlndcn
あらゆるWebサイトの好きな部分に、
この拡張をインストールした人にだけ見える共有メモを貼付けることができます。

きっかけ

きっかけは「はてぶ」のコメントを見ていた時です。
わざわざ別のページで見ないといけないの面倒くさいな、ってところで思いつきました。

Chrome拡張

Chrome拡張おもしろいです!
http://code.google.com/chrome/extensions/trunk/getstarted.html
今まで作った事無くてこれを思いついた時には実現可能かどうかもよくわからなかったんですが
id:bluerabbit さんに教えて頂いた事もあり、
JSが苦手にも関わらず^^大した戸惑いもなくあっという間に作成を始められました。

jsonengine

バックエンドはjsonengineを使っています。
別件でコミッターをやらせて頂く事になっていたため、せっかくなので使おうと決めたのですが、
これがドンピシャ!今回のようなアプリでは最高の選択だったと思います。
Google Accountとの連携部分は自分で作ってコミットしましたが( ꒪⌓꒪)


id:higayasuo さんの2つのエントリーでもありましたが、
http://d.hatena.ne.jp/higayasuo/20101108/1289206846
http://d.hatena.ne.jp/higayasuo/20101109/1289290143
このアプリはまさにそのもので、
AppEngineの使い方としては最高の使い方の一つじゃないかと自負してます(^^;
もし仮にこのアプリがブレイクしても何も怖くないですね。
(マネタイズは考えないといけないですが^^)


jsonengineはまだまだ機能不足の面もあり、
AppEngineのDatastoreを意識しないといけない面もありますが、
今後はもっと使いやすくなるはずです!オススメ!!

今後

メモの色を変えられるとか、Twitterと連携させるとか、
リアルタイムで他人の変更が反映されるとか、いろいろ考えています。
チームエディションも作りたいですね。
シンプルさを保ちつつ、楽しさを提供できればいいなーと思います。

DatastoreのDump/Restoreツールが既存プロジェクトにバインドできるようになりました。

以前こちらで書かせてもらったgobo-toolsですが、
http://d.hatena.ne.jp/knj77/20101007/1286462560
バグ修正と同時に、既存アプリにもバインドできるよう修正を施しましたので紹介させてもらいます。
Slim3には依存していませんので(未確認ですが)ほとんどのアプリで動作できると思います。

gobo-toolsのインストール方法

1.zipのダウンロード

以下のページから最新のzipをダウンロードしてください。
http://code.google.com/p/gobo-tools/downloads/list

ダウンロードしたzipを展開すると以下のものが含まれています。

  • gobo-tools.20101021.jar
  • gdata-media-1.0.jar
  • gdata-docs-3.0.jar
  • google-collect-1.0-rc1.jar
  • gdata-spreadsheet-meta-3.0.jar
  • gdata-spreadsheet-3.0.jar
  • gdata-core-1.0.jar
  • gdata-client-meta-1.0.jar
  • gdata-client-1.0.jar
  • gobo(フォルダ)
2. jarのコピー

1で展開した中にある全てのjarをwar/WEB-INF/lib直下にコピーしてください。

3. JSPのコピー

1で展開した中にあるgoboフォルダをwar直下にコピーしてください。

4. web.xmlの編集

web.xmlに以下の内容を記述してください。

    <servlet>
        <servlet-name>GoboServlet</servlet-name>
        <servlet-class>gobo.GoboServlet</servlet-class>
    </servlet>    
    <servlet-mapping>
        <servlet-name>GoboServlet</servlet-name>
        <url-pattern>*.gobo</url-pattern>
    </servlet-mapping>
    <security-constraint>
        <web-resource-collection>
            <url-pattern>*.gobo</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>admin</role-name>
        </auth-constraint>
    </security-constraint>
5.専用のURLにアクセス

http(s)://your-app-id.appspot.com/index.gobo 拡張子に注意
にアクセスすると、gobo-toolsにアクセスできます。

以上です。

注意事項

仕様として注意してもらいたいポイントを列挙します。

  • Dump/Restoreでは最初にAuthSubの認証があります。(Google Spreadsheetの読み書きを行うため)
  • 内部的に _GOBO_CONTROL_ というKind名でDatastoreに書き込みを行います。(まず無いと思いますが)プロジェクトで左記のKind名をご利用の場合はご注意ください。また、各動作終了後、_GOBO_CONTROL_ というKindは自動的に削除されます。
  • Dumpはスナップショットではありません。TaskQueueで少しづつ取得しながらspreadsheetに書き込みますので、最初の行と最後の行では時間的に差があります。
  • Blob、ShortBlob、Textは対応していません。(Restore時にnullで上書きしないようにはなっています。)
  • Production環境でのDump/Dropスキーマ情報にDatastore Statisticsを参照しますのでStatistics更新前は正しく動作しません。
  • Dumpした結果、全てのデータはダブルクオートで囲まれています。これはSpreadsheetの自動変換を避けるためで、Restore時にはあってもなくても構いません。

その他

バグを見つけた方は @knj77 までご連絡頂くか、
http://code.google.com/p/gobo-tools/issues/list にご登録頂ければと思います(日本語で構いません)
感想、ご要望などもお聞かせ頂けると嬉しいです。


なお、このツールをご利用頂いた結果被った損害については一切の責任を負いかねますのでご了承ください。
特にProduction環境で用いる場合は、事前にステージング用の別アプリIDなどで十分な検証を行う事をお勧めします。

Slim3+MobyletでHTMLが複数回出力されるときの対処法

Slim3Mobyletを組み合わせた場合、なぜかProduction環境でだけ、HTMLが複数回出力される(の後にまたが始まる)ことがあります。

バージョン

Slim3 : 1.0.5
Mobylet : 1.0.6

対応方法

web.xmlのフィルタ対象いじって直ったと思いきや、Slim3のAppRouterが効かなくなったりして紆余曲折あるのですが、
結論としては、以下のコードで直りました。

import javax.servlet.http.HttpServletResponse;

import org.mobylet.core.dialect.MobyletDialect;
import org.mobylet.core.http.MobyletFilter;
import org.mobylet.core.http.MobyletResponse;

public class MobyletFilterWrapper extends MobyletFilter {
    
    protected MobyletResponse wrapResponse(
            HttpServletResponse response, MobyletDialect dialect) {
        return new MobyletResponseWrapper(response, dialect);
    }

}

web.xmlのMobyletFilterの実体を上記クラスに変更します。

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.mobylet.core.dialect.MobyletDialect;
import org.mobylet.core.http.MobyletResponse;

public class MobyletResponseWrapper extends MobyletResponse {

    public MobyletResponseWrapper(HttpServletResponse response,
            MobyletDialect dialect) {
        super(response, dialect);
    }

    public void flushByMobylet() throws IOException {
        super.flushByMobylet();
        if (this.printWriter != null) {
            this.printWriter.close();
        }
    }
}

現象としては、MobyletResponse#flushByMobylet() が複数回実行されて、
MobyletResponseの持つPrintWriterがclose()されていない為に発生しているようなので、
拡張したクラスで明示的にclose()してあげます。

まとめ?

複数回呼ばれる事が間違っているのか、closeしてないのが間違っているのか、
そもそも、どうしてProductionでしか発生しないのか、全然わかりませんがw
ともかく、上記のようにPrintWriter#flush()後にcloseして上げる事で直りました。
これでしばらく様子をみたいと思います。

DatastoreのDump/RestoreをGoogle Spreadsheetで実現するツール

Google App Engineをお使いの方はご存知の通り、
Datastoreのデータの出し入れには、都度プログラムを書く必要があり非常に面倒です。


そこで、以下のようなものを作りました。
http://gobo-tools.googlecode.com/
Google SpreadsheetにDatastoreのデータを出力し、
そこからまたDatastoreに取り込む、というツールです。


デモはこちら。
http://gobo-tools.appspot.com/
Dumpをクリックして(AuthSubの認証があります)「Test2」を選択して実行するのがお勧めです。


GData APIタイムアウトによく遭遇するため500エラーになるかもしれませんが、その時はリロードしてください。
うまくいった場合は、開いたSpreadsheetにもりもり書き込まれるのが面白いです。



Spreadsheetなので手作業で変更できるし、
Spreadsheet自体にアクセス権があれば複数人でテストデータを共有もできます。


他にも、用途としては
アプリ間のデータ移行、初期データの準備をSpreadsheet上でできるように考えています。


現在はそれ自体で一つのprojectなのですが、そのままでは使いづらいので
ktrwjrのように他のprojectでも使いやすいよう、jarをコピーするだけで使えるようにする予定です。

Google App EngineでOpenID + OAuth Hybrid

勢いづいたので、OpenID+OAuth Hybridもアップしました。
http://code.google.com/p/appengine-openid-test/source/browse/#svn/trunk/marketplace-template-hybrid

Hybridとは

OpenIDの認証と一緒に(3-Legged) OAuthの認証を一緒にやったらええやん、というものです。
http://code.google.com/intl/ja/googleapps/domain/sso/openid_reference_implementation.html


ベースになっているのは@shin1ogawaさんのアップしたテンプレートです。
http://shin1o.blogspot.com/2010/04/marketplace-appengine-java.html

Hybrid化

AuthRequestHelperにOpenIDのAxAttributeを追加するのですが、
同時に、requestOauthAuthorization()をつけるとHybridになります。

Consumer登録

Hybridとはいえ、OAuth Consumerになるので
https://www.google.com/accounts/ManageDomains
ドメインの登録が必要です。
(しなくてもエラーにはなりませんが、普通のOpenIDとして動作します。)

GData Client Libraryが未対応

Googleの提供しているGData Client LibraryがHybridに対応できてません^^
具体的には、Hybridの場合、request_token_secretなしでaccess_tokenを取得できるのですが、
GoogleOAuthHelperというクラスでrequest_token_secretを必須としているため、
バリデーションエラーとなってしまいます。


そこで、GDataと同名のパッケージを用意してHybridHelperなるもので対応しました。

ただし

  1. Google Apps Marketplaceでは2-Legged OAuthを使うべき(らしい)
  2. 流用しているライブラリが大きいためSpin-Upに8秒ぐらいかかる

上記の理由により、AppEngineがネイティブにOpenID対応した今では
あまり日の目を見る事はなさそうです。。。が
個人のGoogle Accountを対象としたプロジェクトなど、
もしかしたら役に立つかもしれません。

Google App EngineでGoogle Apps用OpenID

sdk1.3.4でのOpenID対応を実際に試してみました。
コードはこちら(Javaです)
http://code.google.com/p/appengine-openid-test/


以下の記事を参考にさせてもらいました。
@hidemotoNakada さん
http://d.hatena.ne.jp/hidemon/20100521/1274472966

@int128 さん
http://d.hatena.ne.jp/int128/20100525/1274809086


ただし、お二方と違って自分は
web.xmlのsecurity-constraint
を利用しませんでした。

リダイレクト先が気にくわなかったので^^)
代わりにOpenIDFilterを自前で実装しています。

AppEngine でのOpenIDの特徴

sdk1.3.4で追加された機能では、OpenIDのややこしいところが、
AppEngine内でProxy的に実装されているので、
自前アプリからそこにリダイレクトする事で実現されます。
(認証後も同様にProxy的なものを経由するようです。)

userService.createLoginURL()の引数

Google Appsの場合、federatedIdentityにはドメイン名を指定します。
上記Proxyに、
httpから始まったら外部のサービス
そうでなければGoogle Apps
というロジックが入っているのだと思います。