9月
12
2010
2

Twitter4J から OAuth 認証部分だけを利用する方法

※前置き長いです。本題はここから。

9/6 ごろから 9/9 にかけて、TwitMgrSplitwit の OAuth 認証が正しく動作しなくなってしまっていました。
これらは、JavaScript で Twitter API を扱うライブラリとして、TwitAPI.js を使っており、それがうまく動作していなかったのです。で、原因を追ったところ、JavaScript 側ではなく、OAuth 認証を肩代わりするプロキシサーバである taj-proxy 側に問題があることがわかったので、今回はそれを直したときの話です。

そもそも、taj-proxy は、開発当初 GAE/j 上でうまく Twitter OAuth 認証を扱えるライブラリがなかった (と思っていた) ため、OAuth 認証部分をすべて独自実装してました。Twitter 側の何らかの実装の変更により、その独自実装がうまく動かなくなったようなのですが、ぱっと見では全然原因が分かりませんでした。(多分 Signature 周りだとは思う)
それで改めて、Twitter OAuth 認証を扱えるライブラリを探したところ、Twitter4J という超メジャーなライブラリが、GAE/j に対応していることがわかり、早速使用させてもらうことにした次第です。

Twitter4J では、Twitter API と一対一に対応した java のメソッドが用意されており、きわめて簡単に TwitterAPI を利用することができます。(設計思想としては、初代の TwitterAPI.js に似てますね。)
ところが、TwitAPI.js では、将来的な TwitterAPI の拡張もにらんで、任意のパスを渡して TwitterAPI を利用することができるようになっているため、そのままでは JavaScript 側から渡されたパスを Twitter4J のメソッドに翻訳する必要が出てしまい、単に適用するだけでは済みませんでした。

そこで、Twitter4J の便利メソッドは使用せず、Twitter4J として用意されている各種のクラスを使用して、OAuth 部分だけを利用させてもらったので、その方法についてまとめておきます。

ここから本題です。長い前置きでした‥。

リクエストトークンを取得する

Twitter API を OAuth で使用する際に、開発者側で必要な ConsumerKey と ConsumerSecret はすでに取得済みなことを前提とします。もしまだでしたら、ほかの情報を当たってください。
ここではまず、これから始める OAuth 認証のために必要なリクエストトークン (使い捨てパスワードのようなもの) を取得します。

下記の疑似コードでは捨ててますが、consumerKey と consumerSecret から、requestToken と requestTokenSecret を取得するまでがポイントです。この時点ではまだユーザには何も提示しておらず、ここで取得した requestToken を次に使います。また、requestTokenSecret も必ずペアで保持しておきます。

Configuration conf = ConfigurationContext.getInstance();
OAuthAuthorization oauth = new OAuthAuthorization(conf, consumerKey, consumerSecret);
HttpClientWrapper http = new HttpClientWrapper(conf);
try {
    HttpResponse res = http.post(conf.getOAuthRequestTokenURL(), oauth);
    String result = res.asString();
    if (res.getStatusCode() != 200) {
        System.out.println(result);
        return false;
    }
    Map<String, String> results = OAuthUtil.parseResult(result);
    String requestToken = results.get("oauth_token");
    String requestTokenSecret = results.get("oauth_token_secret");
} catch (TwitterException e) {
    e.printStackTrace();
    return false;
}
return true;
public static Map<String, String> parseResult(String result) {
    String[] results = result.split("&");
    Map<String, String> map = new HashMap<String, String>();
    for (String param : results) {
        String[] kv = param.split("=");
        String key = kv[0];
        String value = kv[1];
        map.put(key, value);
    }
    return map;
}
Twitter4J の役者たち
Configuration クラス
Twitter4J の設定情報を保持しています。シングルトンなので、こうしてインスタンスを取得して様々に使用します。
OAuthAuthorization クラス
Twitter4J で OAuth の認証情報を扱うクラスです。この時点ではまだ consumerKey と consumerSecret しか持ちません。
HttpClientWrapper クラス
GAE/j では外部サイトに対してソケットを開くことができず、Apache Commons Http Client などの普通の HttpClient は軒並み全滅という状況の中、HttpClientWrapper は、GAE/j でも利用可能な HttpURLConnection も状況に応じて使用して GAE/j 上でもスムーズな動作を可能とした、超ナイスなクラスです。
独自メソッド
OAuthUtil.parseResult メソッド
HttpResponse#asString() メソッドでは、単にサーバからのリプライを文字列で返してきます。Twitter API の仕様上、OAuth 認証段階では、名前=値&名前=値&名前=値… という文字列が返ってくるので、それを Map にパースするだけです。

OAuth 認証の要求

単に以下の URL をユーザに表示して (通常、ブラウザであればリダイレクト) ユーザからの認証許可を待ちます。
認証が許可されると、ConsumerKey を取得した際に登録したコールバック URL に結果が返ってきます。

https://twitter.com/oauth/authorize?oauth_token=requestToken
https://twitter.com/oauth/authenticate?oauth_token=requestToken

ここで、authorize は、必ず毎回ユーザの手動による認証が必要になります。
authenticate の場合、初回のみ認証が必要なだけで、一回認証してしまえば次回からは自動的にコールバックが呼ばれるようになります。大半のウェブサービスではこちらを使ってますね。
ちなみに TwitAPI.js では、その性質上簡単に認証情報を横取りすることが可能なので、authorize のみ利用可能にしています。

アクセストークンの取得

ユーザから OAuth 認証が許可されると、コールバック URL に結果が返ってきます。その際、リクエストパラメータとして oauth_token が渡されるので、これを requestToken と見なし、ペアで保持しておいた requestTokenSecret を取り出します。

再度 Twitter サーバに問い合わせた結果得られる、oauth_token と oauth_token_secret が、真に重要なアクセストークンになります。これがいわば、OAuth 認証の結果得られた、対象アプリケーション専用のパスワードのようなものです。その際、各ユーザのユニークキーである user_id と表示上の名前である screen_name が得られるので、これらすべてをセットにして保持しておきます。
ただ、screen_name に関してはユーザ設定で変更も可能なので、もしアプリ側でユーザごとの情報を何か保存する場合、user_id に関連づけて保存しておく必要があります。

Configuration conf = ConfigurationContext.getInstance();
AccessToken accessToken = new AccessToken(requestToken, requestTokenSecret);
OAuthAuthorization oauth = new OAuthAuthorization(conf, consumerKey, consumerSecret, accessToken);
HttpClientWrapper http = new HttpClientWrapper(conf);
try {
    HttpResponse res = http.post(conf.getOAuthAccessTokenURL(), oauth);
    String result = res.asString();
    if (res.getStatusCode() != 200) {
        System.out.println(result);
        return false;
    }
    Map<String, String> results = OAuthUtil.parseResult(result);
    String accessToken = results.get("oauth_token");
    String accessTokenSecret = results.get("oauth_token_secret");
    String userId = results.get("user_id");
    String screenName = results.get("screen_name");
} catch (TwitterException e) {
    e.printStackTrace();
    return false;
}
return true;
Twitter4J の役者たち
AccessToken クラス
Twitter4J で OAuth のトークン情報を扱うクラスです。この時点では一時パスワードに相当する、requestToken を保持します。
OAuthAuthorization クラス
前と違って、取得済みのリクエストトークン情報も渡します。こうすることで、先ほどユーザが OAuth 認証した結果を結びつけて Twitter 側に伝えることができます。

Twitter API の呼び出し

accessToken と accessTokenSecret が得られれば、後はそれを使って任意の Twitter API が呼び出せるようになります。
Twitter API は使用する HTTP メソッドにより効果が異なるので GET/POST/DELETE に応じて、使用する Java のメソッドが異なります。

Configuration conf = ConfigurationContext.getInstance();
AccessToken accessToken = new AccessToken(accessToken, accessTokenSecret);
OAuthAuthorization oauth = new OAuthAuthorization(conf, consumerKey, consumerSecret, accessToken);
HttpClientWrapper http = new HttpClientWrapper(conf);
String url = "https://twitter.com/some_api_path.json";
HttpParameter[] parameters = new HttpParameter[]{new HttpParameter(name1, value1), new HttpParameter(name2, value2)};

try {
    HttpResponse res = http.get(url, parameters, oauth);
    // HttpResponse res = http.post(url, parameters, oauth);
    // HttpResponse res = http.delete(url, parameters, oauth);
    String result = res.asString();
    if (res.getStatusCode() != 200) {
        System.out.println(result);
        return false;
    }
    // Document document = res.asDocument(); // for xml
    // JSONObject jsonObj = res.asJSONObject(); // for json object
    // JSONArray jsonArr = res.asJSONArray(); // for json array
} catch (TwitterException e) {
    e.printStackTrace();
    return false;
}
return true;
Twitter4J の役者たち
AccessToken クラス
前と違って、一時パスワードに当たる requestToken ではなく、認証済みの accessToken を保持します。
OAuthAuthorization クラス
認証済みのアクセストークン情報も渡すことで、任意の API を呼び出し可能になります。
url
任意の Twitter API の URL が指定可能です。Twitter API の仕様として「拡張子」に当たる部分を、json とか xml に変えると、Twitter が返す結果のフォーマットを制御できます。詳しくは、Twitter API のドキュメントを参照してください。
HttpParameter クラス
HttpClientWrapper クラスに、任意のパラメータを渡すために使います。どういったパラメータが有効に機能するかは、Twitter API のドキュメントを参照してください。

あとがき

Twitter4J を使用するほとんどの人は、最初から用意されている便利メソッドで十分事足りると思うので、OAuth 部分のみ使用するといった用途は限定的かと思います。例えば、Twitter4J 未対応の新 API を使いたい場合や、今回のケースのように独自のアプリで変わったことをしたい場合などでしょうか。
ただ、そういった用途を想定したかのように、Twitter4J のクラス郡は非常によくできていて、とても使いやすいので助かりました。
改めて、Twitter4J の作者様には謝辞を述べたいと思います。

Written by Otchy in: Development | タグ: ,
4月
19
2009
3

Google App Engine for Java 開発環境を USB メモリで持ち歩く (3)

Google App Engine の Java 開発環境を USB メモリに入れてどこでも開発できる環境を作りました。
レポート第 3 弾。GAE プロジェクトを作成し、最初の Hello world! が表示できるようになるまで。

Google App Engine SDK の設定

最初に Google Plugin をインストールした時と異なるドライブレターで USB メモリを使用している場合、Google App Engine SDK のパスがリンク切れを起こしてしまっています。
自動的にドライブレターの設定を書き換えられるのがベストなのですが、この設定はどうやら Plugin の設定ファイルに、XML がシリアライズされて保存されているため、安全な書き換えは事実上不可能です。
仕方がないので、下記の手順で複数の SDK を登録しておき、ドライブレターの異なる環境によってそれぞれ使い分けるようにします。

ウィンドウ → 設定 → Google → App Engine → 追加ボタン → 参照ボタン → U:\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.2.0.*\appengine-java-sdk-1.2.0 → 表示名 : 任意 (自宅デスクトップ等) → OK ボタン

また、Web Toolkit も使用する場合は、同様の手順で SDK を追加する必要があります。

JRE 自体は、Eclipse 起動時にオプションで指定したものを共有できるのでいいんですが、この Google App Engine の SDK だけはスマートに解決できていないです。
良い解決方法を知っている方がいたら是非教えて下さい。

プロジェクトの新規作成

続いて Hello World を作ります。最初に作るのは Hello World と相場が決まっているのです。オールドタイプですいません。
ではまず、ツールバーのnew_app_buttonボタンをクリックして、ウィザードを起動します。

プロジェクト名 : HelloWorld → パッケージ : helloworld → Use Google Web Toolkit のチェックを外す → Use Google App Engine の Configure SDKs を選択 → 有効な SDK が選択されている事を確認 → OK ボタン → 完了ボタン → ちょっと待つ → 最低限必要なファイルが展開される

なんとこれだけで、Servlet クラスや web.xml はもちろん、その他に最低限必要なファイル一式が全てそろった状態でプロジェクトが作成されます。
Hello World を作成するのに、特別な何かをする必要はありません。

サーブレットコンテナの起動とデバッグ

さあ、いよいよサーブレットとして動作させる時が来ました。また、開発環境を名乗るからには当然、デバッガが正しく動作している事も確認する必要がありますね。

実行 → デバッグの構成 → Web アプリケーション → HelloWorld → デバッグボタン → 初回起動時は Windows ファイアウォールの警告 → ブロックを解除する

これでエラーが発生せず、コンソールに「The server is running at http://localhost:8080/」と表示されれば OK です。
なんて楽なんでしょう。全てのお膳立ては、あらかじめ Google Plugin が済ませておいてくれています。

src/helloworld/HelloWorldServlet.java を開く → 適当にブレークポイントを設定する → ブラウザで、http://localhost:8080/ を開く → HelloWorldServlet リンクを選択 → ブレークポイントでプログラムの実行が一時停止する事を確認

これで問題がなければ、デバッガも正常に動作しています。
ここまでで一応、開発環境の構築は完了です。後は普通の Java やサーブレットの作法に則って、好きなライブラリを追加するなり、好きなフレームワークを導入するなり、開発を進める事が出来ます。

なお、前述の通り、ドライブレターが異なる環境で動作させようとすると、Google App Engine SDK のパスが切れてエラーになってしまいます。
その場合は、Google App Engine SDK を再設定するだけで問題なく動作させられるので、あわてる必要はありません。
ただ、毎回設定し直すのは面倒ですので、もし開発を行う環境で管理者権限があるようだったら、あらかじめ USB メモリのドライブレターを固定させておくのが楽です。

Win +R → diskmgmt.msc → Enter → 対象のドライブを右クリック → ドライブ文字とパスの変更

この設定を 1 回やっておけば、次から同じ USB メモリを指した時はそのドライブに固定されてマウントされるはずです。
様々な環境で他のドライブとかぶらない文字を選んでおくと良いでしょう。

今後の話

3 回に分けて掲載してきた、Google App Engine for java 開発環境の構築はいったんこれで終了です。まあ、正直なところあまり面白くない内容ですよね。
今後、Google App Engine サーバへのデプロイとか、Google App Engine SDK による、Google アカウントの利用とか、DB の利用とかそんなところも、上手く動かせたらレポートしたいと思います。

それと、Java とは直接関係ないのですが、開発環境を USB に入れたついでに、Firefox も USB に入れるといいなぁとか思いました。
他にも、(個人的な) 需要がありそうだったら、PHP 開発環境を USB に入れるとか、MySQL を USB に入れるとかそんなのにも挑戦してみたいですね。PHP なんかの場合は、Apache も入れないといけないので難易度が上がりそうです。

Written by Otchy in: Development | タグ: , , ,
4月
19
2009
2

Google App Engine for Java 開発環境を USB メモリで持ち歩く (2)

Google App Engine の Java 開発環境を USB メモリに入れてどこでも開発できる環境を作りました。
レポート第 2 弾。USB メモリ向け設定を施した Eclipse のインストールから、日本語化を行って Eclipse が起動するまで。

Eclipse のインストール

Eclipse 公式ページから、Eclipse 本体をダウンロードします。最新版である、3.4 系を使用します。

Eclipse IDE for Java Developers → ミラーサイトを選択

ダウンロードしたファイルを解凍して、USB メモリにコピーします。

U:\eclipse

ここでいったん、USB メモリ上の JRE で Eclipse が起動するかの確認をしたいと思います。
Eclipse の起動時パラメータに JRE のパスを指定する事で、任意の JRE で Eclipse を起動する事が出来るのですが、USB メモリでは困った問題が 1 つあります。
USB メモリを利用する環境によってドライブレターが異なるため、ショートカットなどが利用できないという事です。

そこで、VB Script を使用してこの問題を解決します。
以下の内容を eclipse.vbs という名前で USB メモリのルートに保存して下さい。
このスクリプトは、USB メモリを使用している環境に合わせてドライブレターを取得した上で、JRE とワークスペースを指定して Eclipse を起動します。 

Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
drive = fso.GetDriveName(WScript.ScriptFullName)
shell.CurrentDirectory = ".\eclipse"

eclipse = drive & "\eclipse\eclipse.exe"
javaw = drive & "\jdk\jre\bin\javaw.exe"
ws = drive & "\workspace"
cmd = eclipse & " -vm " & javaw & " -data " & ws

Call shell.Run(cmd, 1, False)

ここで作成した、eclipse.vbs を起動すると、USB メモリ上の JRE で Eclipse が起動するはずです。
無事に Eclipse が起動して Welcome 画面が表示されれば OK です。

Google Plugin for Eclipse のインストール

いよいよ、GAE 開発環境のインストールを行います。
起動した Eclipse 上からネットワークインストールが可能なので、下記の通り実行します。
参考) Google App Engine – Installing the Java SDK

Help → Software Updates → Available Software タブ → Add site ボタン → Location: http://dl.google.com/eclipse/plugin/3.4 入力 → OK ボタン → http://dl.google.com/eclipse/plugin/3.4 にチェック → Install ボタン → ちょっと待つ → Next ボタン → I accept … にチェック → Finish ボタン → しばらく待つ → Yes ボタン → Eclipse 再起動

以上で、Google Plugin のインストールは完了ですが、Eclipse にはもう少しプラグインを足しておきます。
個人的には重要度の高いプラグインを導入していますが、この作業は必須でないので、好みによって飛ばしたり、別のプラグインを追加しても良いでしょう。

Eclipse の日本語化 (Pleiades)

Eclipse が起動していたらいったん落とします。
Pleiades 公式サイトより、プラグインをダウンロードして、eclipse をインストールしたフォルダ以下に展開します。

Pleiades 本体ダウンロード → 安定版 1.3.0 → pleiades_1.3.0.zip 解凍 → plugins フォルダ、features フォルダを U:\eclipse 以下にコピー

Pleiades を有効にするために U:\eclipse\eclipse.ini を編集し、最終行に下記を追加します。

-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

ついでなので、昨今の PC スペックに合わせて eclipse.init を多少カスタマイズしておきます。
この辺は各自の環境に合わせて、調整が必要です。

-Xms512m
-Xmx512m

Pleiades を利用する際は、その仕組み上、プラグインが追加されるたびに clean オプション付きで Eclipse を起動しなければなりません。
そのため、Pleiades にはそれを行うためのバッチファイルが同梱されていますが、USB メモリ上では上手く動作しません。

ですので、eclipse.vbs をコピーして、eclipse-clean.vbs を作成しておきます。

Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
drive = fso.GetDriveName(WScript.ScriptFullName)
shell.CurrentDirectory = ".\eclipse"

eclipse = drive & "\eclipse\eclipse.exe -clean"
javaw = drive & "\jdk\jre\bin\javaw.exe"
ws = drive & "\workspace"
cmd = eclipse & " -vm " & javaw & " -data " & ws

Call shell.Run(cmd, 1, False)

作成した eclipse-clean.vbs を使用して Eclipse を起動し、メニューなどが日本語化されていたら、Pleiades の導入は完了です。
clean 起動はかなり時間がかかるので、必要時のみ行うようにした方が良いです。
すなわち、eclipse-clean.vbs は、プラグインを追加するごとに 1 回ずつ使用するスクリプトという事です。

全角スペース、タブの可視化 (JStyle)

Eclipse が起動していたらいったん落とします。
JStype 公式サイトより、プラグインをダウンロードして、eclipse をインストールしたフォルダ以下に展開します。

ダウンロード → Eclipse 3.4.2 用 → jstyle_3.4.2.3.zip 解凍 → plugins フォルダを U:\eclipse 以下にコピー

プラグインの追加を行ったので、1 回 eclipse-clean.vbs で起動させます。
起動後は、Jstyle 推奨の設定を行っておいた方が良いでしょう。

ウィンドウ → 設定 → 一般 → 外観 → 色とフォント → 基本 → テキスト・フォント→ 変更ボタン → MS ゴシック → 標準 → 9 ポイント → OK ボタン → OK ボタン

Written by Otchy in: Development | タグ: , , ,
4月
19
2009
3

Google App Engine for Java 開発環境を USB メモリで持ち歩く (1)

Google App Engine の Java 開発環境を USB メモリに入れてどこでも開発できる環境を作りました。
レポート第 1 弾。前書きと下準備、開発環境の大前提となる JDK を USB メモリに入れるところまで。

はじめに

ecoder をサーバにインストールして、軽い PHP や JavaScript ならどこでも開発できる環境が整ったのですが、大型のアプリや Java の開発となるとなかなか簡単にはいきません。
そうしたところ、ちょうど Google が Google App Engine の Java 対応を発表したので、試してみる事にしました。

開発環境さえ持ち歩く事が出来れば、ローカルで開発して、GAE サーバにアップする事で、どこでも開発できる環境の完成というわけです。
また、どこにでも持ち歩きたかったので、USB メモリ上に環境を構築しましたが、ローカルにインストールする場合でも同様の手順が有効かと思います。
逆に GAE とは関係なく、Eclipse を USB メモリ上で動かす場合でも参考になるはずです。

基本的には Google の公式ドキュメント、Google App Engine – Getting Started: Java をなぞりつつ、USB メモリ上に構築するためのポイントや、開発を便利にするプラスアルファを加えていく予定です。

用意するもの

USB メモリ・・・ Java の SDK や開発環境、開発時のソースや確認用のブラウザなどもまとめて入れてしまうので、同様のものを作るなら 2GB 程度は容量が欲しいところです。
用途次第で好きに選択して下さい。最近は驚くほど安くなっているので、専用に買ってしまってもいいと思います。

Google アカウント・・・さしあたってローカルで動作できる環境を構築しますが、最終的に GAE で公開するためには Google のアカウントが必要です。

Java の知識・・・本エントリは、あらかじめ Java での開発の知識のある方を対象としています。

Windows OS ・・・対象としている OS は Windows です。XP 環境で確認していますが、恐らく 2000 と Vista では同様に動作するのではないかと思われます。

JDK のインストール

まず、Java のサイトからインストーラをダウンロードしてきます。

JDK 6 Update 13 → Download → Platform: Windows, Language: Multi-language, I agree… → Continue → jdk-6u13-windows-i586-p.exe

次にインストーラを起動しますが、いったんローカルの HDD にインストールしてから、インストール後に必要なファイルを USB メモリにコピーして使います。
直接 USB メモリを指定してインストールする事も可能ですが、USB メモリが抜かれている時に様々な問題が発生すると予想されるので、やらない方が無難です。

全てのブラウザを閉じる(Java プラグインのため) → jdk-6u13-windows-i586-p.exe を実行 → 同意する → 次へ → しばし待つ → (JREインストール先の選択) 次へ → しばし待つ → 完了

インストールが正常に完了したら、次は JDK を USB メモリにコピーします。
また、これ以降 USB メモリのドライブレターを U として記述していくので、各自の環境に合わせて読み替えて下さい。
デフォルトの設定で JDK をインストールしていると下記のパスに JDK がインストールされているはずなので、それぞれ USB メモリにコピーします。

C:\Program Files\java\jdk1.6.0_13

U:\java\jdk1.6

以上で、JDK のインストールは完了です。
別途、パスを通したりする作業が必要なのですが、USB メモリは刺した環境によってドライブレターが変わるという問題があるので、その解決は別の項で説明します。

Written by Otchy in: Development | タグ: , , ,

Powered by WordPress | Aeros Theme | TheBuckmaker.com