月別: 2011年6月

ここ最近のことを適当に

android用の神経衰弱ゲームを公開しました(・∀・)
The Match-up(Memory) game for android was released!

Google Play:
Mole's Match-up.

Introduction page:
Mole’s Match-upをリリースした∩( ・ω・)∩


Eclipse 3.7 Indigo

Eclipse 3.7 Indigoがリリースされた。

詳しいことはわからないけれど(ノ∀`)

Eclipse Indigoがリリースによると

Maven統合(M2E)、Maven開発プロセスとの緊密な統合を提供する
WindowBuilder、Java (SWT と Swing)用のドラッグアンドドロップGUIエディター、 GoogleがInstantiations買収後に寄贈した
EGit and JGit、リリースと一緒にバージョン1.0製品としてリリースされた

などの追加があったようで。

MavenもEGitもプラグインが含まれてはいるけれども、インストールされている
わけではない模様。Pleiades All in OneではEGit導入済みだった。(EEのみかも)

WindowBuilderも利用してみようかみまいか悩みどころ。
以前、VisualEditorだったかを入れてえらく不安定になった記憶が(´・ω・`)
Swing、SWT用ということはJavaFX2.0にはいずれ対応するのかな?
NetBeansではJavaFX2.0用のスタンドアロンのGUIツールをリリースするとか
しないとかいう話だったので、Eclipse側はちょっとおいてかれちゃう感じか。

どうも3.7ではJavaSE7のプロジェクトコインをサポートをせず、3.7.1でサポートする
予定らしいので、それまでにプロジェクトコインを確かめたいならNetBeansをいじる
しかないのかなぁ。

まあその辺のことはどーでもいいけども、

E4と一緒に、Eclipse Orion 0.2は、完全にwebホストのIDEでwebブラウザーでリアルタイムな編集ができるように、JavaScriptプラグインを使っている。テスト用に実験的なorion.eclipse.org が入手可能である。

これは…すっかり忘れていたWeb IDE…( ;・´ω・`)ゴクリッ

WebベースのIDEにはさまざまなプロダクトが開発されているが、今回紹介したOrionを含めまだ実用レベルに到達しているものは存在しないのが実情だ。
また、Orionの開発チームの一人であるBoris Bokowski氏のブログによると、Orionは現在のEclipseのような高機能なIDEを直接置き換えるものではなく、Webアプリケーションのフロントエンドの開発における軽量なIDEを目指しており、ファイルブラウザ、エディタ、デバッガ、バージョン管理といったシンプルな機能を持ったIDEで充分であるという方向性を採っているようだ。
(Web IDEの本命か? Eclipse Orionを試してみる)

上の機能に入力補完がついたらそれだけでもいいのになぁ(・∀・) Weblipseや。
NetbookやchromeOSマシンでも開発可能になんのかな?
もしかしたらAndroidPadからとかでも可能になるのかな。早く実用レベルになるといいなぁ。


Google Developer Day coming to a city near you in 2011

November 1: Tokyo, Japan

なん…だと…( ;・´ω・`)ゴクリッ 今年も東京でやるんだ。
※追記 東京じゃなくてパシフィコ横浜みたい
Google Developer Day 2011 Japan を開催します

まあGDD自体はどうでもいいけども、その本編であるDevQuizが…奴が来る( ・´ω・`)

暑い季節だったら受かっても行く気がしないからあれなので、必然的にDevQuizeに
参加出来ないけど、11月ならなんとか大丈夫だ。まあ暖房で汗かくんだけどね(・ω・`;)

今年はどんな問題だろうか。今年は出来るだけ手入力突破という情けない方法に
頼らない形でクリアしたいけれど、結局力業に頼ることになるんだろうなぁ(・∀・)イヒヒ

コメントの

Where is Spain? Where is Barcelona? :(

Toronto…? No toronto? :(

がなんか可愛いw スペイン(・ω・`≡´・ω・)ドコー?ナイノー?

参加賞はなんだろう、あのなんか違うような気がするゴードンのぬいぐるみとかかな


Google+ プロジェクト

ごっぐるぷらす…(´・ω・`)?

Google+がカッコイイ理由:それはオリジナルMacintosh開発チームのアンディー・ハーツフェルド

よくわかんないけどカッコイイらしい。

Google、新プロジェクト ” Google+ ” でソーシャル分野に再挑戦によると

Google+ の題目は “Real-life sharing, rethought for the web”(「現実世界の人間関係をウェブで」)。現実でのコミュニケーションや共有にあるニュアンスや豊かさをオンラインでも再現する試みです。

ふーむ、わかったようなわからないような。取り敢えずソーシャルに再挑戦して、
今のところ招待制なのか。まあ、招待されても特に招待する相手がいないからいいか(ノ∀`)

モバイル用のアイコンを見てふと思ったが、日テレのCS放送のG+とちょっと似てる。
こっちは小文字だから大丈夫か。
あとGoogle+1と混ざっちゃって検索しづらくなったりしないのかな


Google Swiffy

ごっぐるすうぃっふぃー…(´・ω・`)?

グーグル、FlashをHTML5に変換するツール「Swiffy」を発表

SWFファイルにこのツールを適用すると、SWFファイルがJSONファイルに変換され、HTML、SVG(Scalable Vector Graphics)、CSS(Cascading Style Sheets)を使ってレンダリングされる。

ヘー(・∀・) と思ったが手持ちにswfファイルがなくて実際の動作を確かめられなかった_| ̄|○

お試し用のswfも用意しておいてくれればいいのに(´・ω・`)


X PLATE × DELL Streak

一応イーモバで電話も通信も出来るから、そろそろwillcomを解約しようと思っている
ところなのだけれども、これはどうなんだろ。softbankに金を払うのは嫌だなぁ(´・ω・`)
SIMを引き抜いてWifiでStreakが使えれば考えてもいいけれど。
SIMフリーとかその辺のことが全くわからない…我ながら疎すぎる…

Making cross-site requests

android用の神経衰弱ゲームを公開しました(・∀・)
The Match-up(Memory) game for android was released!

Google Play:
Mole's Match-up.

Introduction page:
Mole’s Match-upをリリースした∩( ・ω・)∩


http://code.google.com/intl/ja/webtoolkit/doc/latest/tutorial/Xsite.html

  クロスサイトリクエストの作成

この時点で、クライアントサイドのコードで株価データをシミュレートするストックウォッチャー(株価監視)アプリケーションの最初の実装の修正をしています。現在の実装ではローカルサーバからJSONフォーマット化されたデータを取得しています。 
このセッションでは代わりにリモートサーバを呼び出します。そうするには、SOP (Same Origin Policy)の制約を回避する必要があります。 
  1. 要件と設計のレビュー: アクセスの制約と非同期通信
  2. リモートサーバ上でのJSONデータソースの作成
  3. リモートサーバからのデータのリクエスト
  4. レスポンスの処理
  5. テスト
Note: GWTアプリケーションにおけるクライアント-サーバ間通信についての幅広いガイドはCommunicate with a Serverを見てください。

 始める前に

StockWatcher プロジェクト

このチュートリアルはGWTの概念とBuild a Sample GWT Application チュートリアルで作成した
StockWatcherアプリケーションを基にしています。 もしGWTアプリケーション作成チュートリアルを
終えておらずGWTの概念がある程度わかっているなら(慣れ親しんでいるなら)、
ここでStockWatcherプロジェクトをコードとしてインポートすることが出来ます。 
  1. StockWatcher projectをダウンロードします。
  2. ファイルを解凍します。
  3. エクリプスへプロジェクトをインポートします。
    1. ファイル メニューから、インポートメニューオプションを選択します。
    2. [一般]-[既存プロジェクトをワークスペースへ]を選択します。次へ(N)ボタンをクリックします。
    3. [ルート・ディレクトリーの選択(T)]でブラウズしStockWatcherのあるディレクトリ
      (ファイルを解凍した場所から)を選択します。完了(F) ボタンをクリックします。
antを使用している場合は、StockWatcher/build.xmlの何処にGWTを解凍したかを指す
 gwt.sdk プロパティを編集します。

実際にこのチュートリアルを実行する為に、StockWatcherを実行しているサーバとは別に、あなたのマシン上でPHPスクリプトかPythonスクリプトを実行できるサーバのどちらかへのアクセスが必要です。

 1. 要件と設計のレビュー

リモートサーバ上のデータにアクセスするために現在のStockWatcherの実装を修正するには、取り組むべき二つの課題があります:
  • アクセス制限: SOP (Same Origin Policy セイムオリジンポリシー)
  • 非同期通信


第2回 Same-Originポリシーと迂回技術Same-Origin ポリシー

アクセス制限: Same Origin ポリシー

Same Origin Policy (SOP)とはクライアントサイドJavaScriptコードが同じドメイン、プロトコル、ポートから発していない資源(リソース)と対話することを制限するブラウザのセキュリティ対策です。
この3種の値が同じ場合のみ、ブラウザは2ページが同じ発生元をもつ考えます。
例えば、http://abc.com:80上のWebページで実行されているStockWatcherアプリケーションは、異なるドメイン、http://xyz.comからロードされた株データと対話できません。 ポートが異なる場合(例えばhttp://abc.com:81)、同じドメインから株データであってもロードすることは出来ません。
SOPの背後にある考えは、セキュリティ上の理由から、ブラウザは任意のWebサイトの内容を信頼すべきではないということです。悪意あるWebページはデータを盗むまたはセキュリティを破るコードを注入することが出来ます。
従って異なるドメインまたはポートからのJSONフォーマット化された株データへのアクセスは、現在の実装では機能しません。webブラウザはJSONを取得するためのHTTPコールをブロックするでしょう。

SOPとGWT上でのその影響についてのより詳しい情報は What is the Same Origin Policy, and how does it affect GWT?を読んでください。

SOPの回避

SOPセキュリティを回避するための選択肢は二つあります:
  • あなたのサーバ上でのプロキシ
  • <script>タグ内へのJSONレスポンスのロード
あなたのサーバ上でのプロキシ
最初の選択肢はSOPのルールに従って行動し、ローカルサーバ上にプロキシを作成します。それからローカルサーバへHTTPコールを送り、ローカルサーバにリモートサーバからのデータを取りに行かせます。あなたのWebサーバ(ローカルサーバ)上で実行されるコードはSOPの制約を受けないのでこれは機能します。クライアントサイドコードのみです。
特にStockWatcherアプリケーションでは、リモートサーバからJSONエンコード化された株式相場をダウンロード(と多分キャッシュ)するためのサーバサイドコードを書くことによってこの方法を実装出来ます。それからローカルサーバからデータを取得するための望みどおりの任意のメカニズムを使用出来ます: GWT RPC または RequestBuilderを使用した直接のHTTPコール
このアプローチのマイナス面の一つは、サーバサイドコードの追加が必要な事です。 もう一つは、余分なHTTPコールがリモートコールの呼び出し時間を増加させ、webサーバの作業負担を追加するということです。
<script>タグ内へのJSONレスポンスのロード
もう一つの選択肢は<script>タグ内へ動的にJavaScriptをロードすることです。クライアントサイドのJavaScriptは、HTMLドキュメントオブジェクトモデル(DOM)内の任意の他の要素のように、<script>タグを操作出来ます。クライアントサイドコードはページへ新しいJavaScriptを自動的にダウンロードして実行するために<script>タグのsrc属性をセット出来ます。 
この方法はSOPの制約を受けません。従って、リモートサーバからJavaScript(及びJSON)をロードするためにこの方法は効果的に使用できます。
これはリモートサーバからJSONフォーマット化された株データを取得するために使用する方法です。

非同期通信

<script>タグへのJavaScriptの動的ローディングはSOP問題を解決しますが、別の問題を持ち込みます。JavaScriptをロードするためにこのメソッドを使用した時、ブラウザは非同期にコードを取得しますが、その取得が完了した時の通知をしません。その代わりに新しいJavaScriptを単純に実行します。しかしながら、当然、JSONは実行可能なコードを含むことは出来ません。二つを一緒に置いてください。<script>タグを使用してプレーンJSONデータをロードすることが出来ないことがわかります。 

JSON with Padding (JSONP)

コールバック問題を解決するためにそのコール(呼び出し)自身の入力引数としてコールバック関数の名前を指定することが出来ます。そうするとwebサーバはその関数へのコールでJSONレスポンスをラップします。 このテクニックは JSON with Padding (JSONP)と呼ばれます。 ブラウザが<script>タグの新しい内容のダウンロードを終えた時、コールバック関数は実行されます。
callback125([{"symbol":"DDD","price":10.610339195026,"change":0.053085447454327}]);
Google Data APIs はこのテクニックをサポートします。
StockWatcherのための、クライアントサイドコード内の追加の要件はHTTPリクエストのコールバックとして使用するJavaScriptの関数の名前を含めることです。

実装計画

クロスサイトリクエストを取り巻くSOP問題を理解している今、この実装とローカルサーバからJSONデータを取得してくる実装とを比較します。あなたは既存の実装をいくらか修正しなければなりませんが、同様にいくつかのコンポーネントは再利用することが出来ます。作業のほとんどは新しいメソッド、getJSONを書くことです。このメソッドはリモートサーバをコール(呼び出し)します。
タスク 同一サイト用
インプリメンテーション(実装)
クロスサイトインプリメンテーション(実装)
コールの作成 リクエストビルダーによるHTTP 付加されたコールバック関数の名前を伴うJSONデータのURLであるsrc属性をもつ<script>タグを埋め込んでください?
サーバサイドコード  JSON文字列を返します JSON文字列を伴うJavaScriptコールバック関数を返します
レスポンスの処理 JSON文字列をJavaScriptオブジェクトへ変更する為にJavaScriptのeval()関数を使用 既にJavaScriptオブジェクト;StockData配列にキャストされる
データオブジェクト オーバーレイタイプを作成: StockData オーバーレイタイプを再利用
エラー処理 エラーメッセージを表示するためのレーベルウィジェットを作成 レーベルウィジェットを再利用

 2. データソースの作成

このチュートリアルではStockWatcherはSOPの制約に遭遇するので株データをセットアップするための二つの選択肢があります。
  1. PHPがインストールされたサーバへアクセス出来る場合、JSONフォーマット化された株データを生成するために以下のPHPスクリプトを使用出来ます。
  2. サーバを持っていないけれど、あなたのマシンにPythonがインストールされている場合、StockWatcherが実行されているポートと異なるポートから株データを提供するために以下のPythonスクリプトを使用出来ます。

実際に異なるサーバを使用する

webサーバにアクセス出来たら、JSONPを返す為の以下のPHPスクリプトを使用することが出来ます。 
  1. テキストファイルを作成し stockPrices.phpという名前にします。

    header('Content-Type: text/javascript');
    header('Cache-Control: no-cache');
    header('Pragma: no-cache');

    define("MAX_PRICE", 100.0); // $100.00
    define("MAX_PRICE_CHANGE", 0.02); // +/- 2%

    $callback = trim($_GET['callback']);
    echo $callback;
    echo '([';

    $q = trim($_GET['q']);
    if ($q) {
    $symbols = explode(' ', $q);

    for ($i=0; $i
    $price = lcg_value() * MAX_PRICE;
    $change = $price * MAX_PRICE_CHANGE * (lcg_value() * 2.0 - 1.0);

    echo '{';
    echo ""symbol":"$symbols[$i]",";
    echo ""price":$price,";
    echo ""change":$change";
    echo '}';

    if ($i < (count($symbols) - 1)) {
    echo ',';
    }
    }
    }

    echo ']);';
    ?>
  2. 別のサーバにPHPスクリプトをコピーします。
  3. ブラウザを開き、JSONデータ用のリクエストを作成します。
    http://[www.myStockServerDomain.com]/stockPrices.php?q=ABC
  4. JSON文字列が返されます。
    [{"symbol":"ABC","price":81.284083,"change":-0.007986}]
    しかしながら、 次のセクションでわかるように、StockWatcherアプリケーションは自身のクライアントコードからこのリクエストをすることは出来ません。
  5. コールバック関数の名前を付加することによってJSONP用のリクエストをします。
    http://[www.myStockServerDomain.com]/stockPrices.php?q=ABC&callback;=callback125
  6. JSONはコールバック関数に埋めこまれて返されます。
    callback125([{"symbol":"ABC","price":53.554212,"change":0.584011}]);

セカンドサーバのシミュレーション(Pythonによる模擬セカンドサーバ)

リモートサーバへ出来ない場合でも、あなたのローカルマシンにPythonがインストールされているのなら、リモートサーバをシミュレート出来ます。異なるポートへHTTPリクエストをした場合、あなたは まるで異なるドメインへアクセスしようとしているかのようにSOPの制約を受けます。
あなたのローカルマシンの異なるポートからデータを提供するために以下のスクリプトを使用します。 個々の株のシンボルのためにPythonスクリプトはJSONフォーマットのランダムな価格を生成し、値を変更します。BaseHTTPServer.HTTPServerコンストラクタ内でそれはポート 8000で実行されていることに注意してください。さらにスクリプトはコールバッククエリ文字列パラメータをサポートすることにも注意してください。
  1. Pythonスクリプトを作成し、quoteServer.pyとして保存します。
    #!/usr/bin/env python2.4
    #
    # Copyright 2007 Google Inc. All Rights Reserved.

    import BaseHTTPServer
    import SimpleHTTPServer
    import urllib
    import random

    MAX_PRICE = 100.0
    MAX_PRICE_CHANGE = 0.02

    class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):

    def do_GET(self):
    form = {}
    if self.path.find('?') > -1:
    queryStr = self.path.split('?')[1]
    form = dict([queryParam.split('=') for queryParam in queryStr.split('&')])

    body = '['

    if 'q' in form:
    quotes = []

    for symbol in urllib.unquote_plus(form['q']).split(' '):
    price = random.random() * MAX_PRICE
    change = price * MAX_PRICE_CHANGE * (random.random() * 2.0 - 1.0)
    quotes.append(('{"symbol":"%s","price":%f,"change":%f}'
    % (symbol, price, change)))

    body += ','.join(quotes)

    body += ']'

    if 'callback' in form:
    body = ('%s(%s);' % (form['callback'], body))


    self.send_response(200)
    self.send_header('Content-Type', 'text/javascript')
    self.send_header('Content-Length', len(body))
    self.send_header('Expires', '-1')
    self.send_header('Cache-Control', 'no-cache')
    self.send_header('Pragma', 'no-cache')
    self.end_headers()

    self.wfile.write(body)
    self.wfile.flush()
    self.connection.shutdown(1)

    bhs = BaseHTTPServer.HTTPServer(('', 8000), MyHandler)
    bhs.serve_forever()
  2. メインのStockWatcherディレクトリへスクリプトを保存します。
  3. あなたのPATHにPythonインタプリタがあることを確認してください。(※PATHが通ってること?)
  4. スクリプトを実行します。
    コマンドシェルから python quoteServer.pyと入力します。
    サーバは起動しますが、直接にはいかなる出力も目にすることはありません。(HTTPリクエストごとに記録されます。)
  5. ブラウザを開き、JSONデータ用のリクエストをします。
    http://localhost:8000/?q=ABC
  6. JSON文字列が返されます。
    [{"symbol":"ABC","price":81.284083,"change":-0.007986}]
    しかしながら、 次のセクションでわかるように、StockWatcherアプリケーションは自身のクライアントコードからこのリクエストをすることは出来ません。
  7. コールバック関数の名前を付加することによってJSONP用のリクエストをします。
    http://localhost:8000/?q=ABC&callback;=callback125
  8. JSONはコールバック関数に埋めこまれて返されます。
    callback125([{"symbol":"ABC","price":53.554212,"change":0.584011}]);

 3.リモートサーバからのデータリクエスト

サーバがJSON文字列またはJSONPとしていずれかの株データを返すことを確認した今、あなたはリクエスト及びJSOPを処理するようにStockWatcherを更新出来ます。RequestBuilderコードはgetjsonメソッドへの呼び出しに置き換えられます。最初のパラメータは各HTTPリクエストを一意的に識別するIDナンバーです。 

URLの指定

クエリしている株コードとコールバック関数の両方を含むようにするためにクエリURLを更新します。個々のコールバック関数は一意的なIDナンバーを持ちます。

JSON_URLの更新

これはデータが異なるドメインまたは異なるポートから提供されるかに依存する実装を結果として生じることが唯一の違いです。

  1. StockWatcherクラスで、以下のように JSON_URL 定数を変更します:
    変更前:

    private static final String JSON_URL = GWT.getModuleBaseURL() + "stockPrices?q=";
    異なるポート(Pythonスクリプト)から株データが提供される場合、 JSON_URLは以下のよう変更します:

    private static final String JSON_URL = "http://localhost:8000/?q=";
    異なるドメイン(PHPスクリプト)から株データが提供される場合、ドメインとstockPrices.phpスクリプトへのフルパスを指定します:

    private static final String JSON_URL = "http://www.myStockServerDomain.com/stockPrices.php?q=";
  2. コールバックIDの値を保持する変数を作成します。
    private Label errorMsgLabel = new Label();
    private int jsonRequestId = 0;
  3. リモートサーバからのプレーンJSONデータの取得を試みます。
    開発モードでStockWatcherをデバッグします。
    株コードを入力します。
  4. StockWatcherはエラーメッセージを表示します: Couldn’t retrieve JSON.
    SOPエラーを修正するために、次のセクションでコールバック関数を伴ったJSONを詰めます。 

 コールバックメソッドの作成

セイムサイト(クライアントとサーバがSOP制約を受けない)実装では、JSON URLが株コードに付加され、それからサーバへHTTP GET リクエストが送信されました。HTTPリクエストを構築する為にRequestBuilderを使用しました。
クロスサイト実装では、JSON URLはコールバックメソッドにラップされます。RequestBuilderのコードはJSNI関数のgetJSON(int, String, StockWatcher)によって置き換えられます。最初のパラメータは一意的に識別出来る各HTTPリクエストのIDナンバーです。
getJSONメソッドはサーバを呼び出すJavaScriptを作成します。

refreshWatchList メソッドの更新

  1. refreshWatchList メソッドを更新します。
    /**
    * Generate random stock prices.
    */
    private void refreshWatchList() {
    if (stocks.size() == 0) {
    return;
    }

    String url = JSON_URL;

    // Append watch list stock symbols to query URL.
    Iterator iter = stocks.iterator();
    while (iter.hasNext()) {
    url += iter.next();
    if (iter.hasNext()) {
    url += "+";
    }
    }

    // Append the name of the callback function to the JSON URL.
    url = URL.encode(url) + "&callback;=";

    // Send request to server by replacing RequestBuilder code with a call to a JSNI method.
    getJson(jsonRequestId++, url, this);

    }
  2. エクリプスはgetJsonにフラグをつけます。
    コンパイルエラーは無視します;あなたはすぐにこのメソッドを書きます。
  3. RequestBuilderのコードをまだ削除していない場合は削除してください。
    RequestBuilderのコードはgetJsonメソッドへの呼び出しへ置き換えます。従って、refreshWatchtList内の以下のコードは最早必要ではありません:
    // Send request to server and catch any errors.
    RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);

    try {
    Request request = builder.sendRequest(null, new RequestCallback() {
    public void onError(Request request, Throwable exception) {
    displayError("Couldn't retrieve JSON");
    }

    public void onResponseReceived(Request request, Response response) {
    if (200 == response.getStatusCode()) {
    updateTable(asArrayOfStockData(response.getText()));
    } else {
    displayError("Couldn't retrieve JSON (" + response.getStatusText()
    + ")");
    }
    }
    });
    } catch (RequestException e) {
    displayError("Couldn't retrieve JSON");
    }

 リモートサーバへの呼び出しの実行

以下の変更はこの実装で最も重要な変更です。リモートサーバへの呼び出しの実行に<script>タグのsrc属性を使用することによってSOPの制約を回避します。
このJSNI メソッド (getJSON)は動的にロードされる<script>タグを作成します。src属性はコールバック関数の名前が付加されたJSONデータのURLです。スクリプトが実行されると、 パッドされたJSONを取ってきます; JSONデータはコールバック関数の引数として渡されます。 コールバック関数が実行されると、JavaのhandleJsonResponseメソッドを呼び出し、JavaScriptオブジェクトとしてJSON
データを渡します。
この実装は埋めこまれた手書きのJavaScriptを含むだけではなく、ブリッジメソッド(開発中、Javaソースコードへコールバックするためのテクニック)を使用します。(StockWatcherをコンパイルする時、クライアントサイドJavaコードは全てJavaScriptへコンパイルされることを思い出してください)

getJSONメソッドの実装

  1. StockWatcherクラスへgetJsonメソッドを追加します。
    /**
    * Make call to remote server.
    */
    public native static void getJson(int requestId, String url,
    StockWatcher handler) /*-{
    var callback = "callback" + requestId;

    // [1] Create a script element.
    var script = document.createElement("script");
    script.setAttribute("src", url+callback);
    script.setAttribute("type", "text/javascript");

    // [2] Define the callback function on the window object.
    window[callback] = function(jsonObj) {
    // [3]
    handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
    window[callback + "done"] = true;
    }

    // [4] JSON download has 1-second timeout.
    setTimeout(function() {
    if (!window[callback + "done"]) {
    handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(null);
    }

    // [5] Cleanup. Remove script and callback elements.
    document.body.removeChild(script);
    delete window[callback];
    delete window[callback + "done"];
    }, 1000);

    // [6] Attach the script element to the document body.
    document.body.appendChild(script);
    }-*/;

実装の注意

  • [1] このスクリプトは<script>要素をセットアップすることによって開始します。src属性は、コールバック関数にラップされたJSONデータを取得するURLを指します。
  • [2] コールバック関数はブラウザのwindowオブジェクト上で定義されます。引数としてサーバによって返されたJSONデータであるJavaScriptオブジェクトを受け取ります。
  • [3] コールバック関数はJavaメソッド handleJsonResponseへJavaScriptオブジェクトとしてJSONデータを渡します。
  • [4] 無応答のサーバやネットワークの問題をチェックするためにタイムアウト関数を定義します; JSONコールバックが呼ばれたかどうかわかるフラグをチェックします。
  • [5]タイムアウト関数が完了する前に、windowから新しい<script>要素とコールバック関数を除去します。
  • [6] 最後に動的にロードされた<script>要素をHTMLドキュメントボディへ添付するためにappendChild()を呼び出します。これはwebブラウザにsrc属性によって参照されるJavaScriptをダウンロードさせます。
未完了の複数のリクエストの処理
この実装は未完了の複数のリクエストがある場合、コールバック関数の名前をシーケンシャルに生成します。特にhandleJsonResponse(JavaScriptObject)メソッドを呼び出すために使用される文法に注目してください:
handler.@com.google.gwt.sample.stockwatcher.client.StockWatcher::handleJsonResponse(Lcom/google/gwt/core/client/JavaScriptObject;)(jsonObj);
JSONオブジェクトがダウンロードされたら、JSNIメソッド内のコールバックがJavaメソッド handleJsonResponseへデリゲート(委譲)していることがわかります。

ブリッジメソッドについて

JavaScriptからJavaメソッドを呼び出すことはJNIでC言語のコードからJavaメソッドを呼び出すに多少似ています。 特に、JSNIは オーバーロードされたメソッドと区別するためにJNIマングルドメソッドシグニチャアプローチを借りています。JavaメソッドへのJavaScriptの呼び出しは以下の形式になります:
[instance-expr.]@class-name::method-name(param-signature)(arguments)

※mangle … 〈…を〉めった切りにする/(間違いや不適切な引用などで)〈文章などを〉わからなくする; ぶちこわす/〈洗濯物などを〉水絞り機にかける.
name mangling … 名前修飾 プログラム内の各種実体に一意の名前を与えることで、様々な問題を解決する(name mangling)
name mangling と extern “C”What’s in Name Mangling?を読むと、C++でシグネチャを一意的なシンボル名に変換することらしい。
5.4 ファイル名の短縮 (Name Mangling) と大文字小文字 ではロングファイルネームを可能にするための手法として説明されている。
weblioの説明の通り、一意的な名前を用いて何らかの問題解決をはかることらしい。

コンポーネント 説明
[instance-expr.] インスタンスメソッドを呼び出す時に存在しなければならず、スタティックメソッドを呼び出す時は存在してはいけません。 handler.
(StockWatcher object instance)
@class-name StockWatcherクラスの完全修飾名 @com.google.gwt.sample.stockwatcher.client.StockWatcher
::method-name 呼び出すメソッドの名前 ::handleJsonResponse
(param-signature) JNI構文で定義された handleJsonResponse メソッドシグニチャ (Lcom/google/gwt/core/client/JavaScriptObject;)
(arguments) JSONデータを含んだjsonObj (jsonObj)
JavaScript実装のJSNIメソッドからのJavaオブジェクトの操作についての更なる情報は開発者ガイドのAccessing Java Methods and Fields from JavaScriptを見てください。

 4. レスポンスの処理

この時点であなたの作業のほとんどは済みます。唯一の違いは返ってくる値が既にJavaScriptオブジェクトであり、JSON文字列ではないということです。従って、最早asArrayOfStockDataメソッドで、JSON文字列を変換するためにJavaScript eval()関数を使用する必要はありません。

handleJsonResponse メソッドを実装する

サーバからレスポンス(応答)を受け取ったら、価格と変動値フィールドへ反映させるためにupdateTableメソッドを呼び出します。あなたは依然としてセイムサイト実装で書いたオーバーレイタイプ(StockData)とJsArray(asArrayOfStockData)を使用しているでしょう。
サーバからレスポンスが来ない場合、メッセージを表示します。セイムサイト実装で作成した、同じdisplayErrorメソッドとレーベルウィジェットを使用出来ます。
  1. StockWatcherクラスへhandleJsonResponseメソッドを追加します。
    /**
    * Handle the response to the request for stock data from a remote server.
    */
    public void handleJsonResponse(JavaScriptObject jso) {
    if (jso == null) {
    displayError("Couldn't retrieve JSON");
    return;
    }

    updateTable(asArrayOfStockData (jso));

    }
    エクリプスはJavaScriptObjectにフラグをつけます。
  2. import宣言を追加します。
    import com.google.gwt.core.client.JavaScriptObject;
    エクリプスはasArrayOfStockDataにフラグをつけます。
    asArrayOfStockData はJavaScriptObjectではなくStringを期待します。

arrayOfStockDataメソッドを修正する

この実装ではレスポンスはStringではなくJavaScriptオブジェクトです。あなたの次のステップはasArrayOfStockDataメソッドを修正することです。JSON文字列をJavaScript配列に変換するよりも、JSNIメソッドから返されたJavaScriptオブジェクトをStockDataの配列としてキャストする必要があります。
  1. asArrayOfStockData メソッドを以下のように修正します:
    変更前:

    /**
    * Convert the string of JSON into JavaScript object.
    */
    private final native JsArray asArrayOfStockData(String json) /*-{
    return eval(json);
    }-*/;
    変更後:

    /**
    * Cast JavaScriptObject as JsArray of StockData.
    */
    private final native JsArray asArrayOfStockData(JavaScriptObject jso) /*-{
    return jso;
    }-*/;

 5. テスト

あなたが異なるドメインまたは異なるポートのどちらかからJSONフォーマット化された株データを提供することを選択したかに関わらず、新しいStockWatcher実装はいかなるSOPアクセス制約をも回避して株データを取得出来るべきです。

開発モードでテストする

異なるポートから株データを提供する

  1. Pythonサーバが実行されていることを確認します。
    もし実行されていなかったら、コマンドラインでpython quoteServer.pyを入力します。
  2. 開発モードで実行されているブラウザ内で、StockWatcherをリフレッシュします。
  3. 株コードを追加します。
    StockWatcherは価格と変動データを表示します。現在、情報は異なるポートから来ます。
  4. Pythonサーバをシャットダウンします。
    StockWatcherはエラーを表示します: Couldn’t retrieve JSON
  5. Pythonサーバを再起動します。
    StockWatcherはエラーを消去し、価格と変動の更新を表示し続けます。

異なるドメインから株データを提供する

  1. 開発モードで実行されているブラウザ内で、StockWatcherをリフレッシュします。
  2. 株コードを追加します。

    StockWatcherは価格と変動データを表示します。現在、情報はリモートサーバから来ます。

  3. StockWatcher.javaで、JSON_URLの値を不正な値に変更します。
  4. 開発モードで実行されているブラウザ内で、StockWatcherをリフレッシュします。
    株コードを追加します。
    StockWatcherはエラーを表示します: Couldn’t retrieve JSON
  5. StockWatcher.javaで、JSON_URLの値を正しい値に直します。
  6. 開発モードで実行されているブラウザ内で、StockWatcherをリフレッシュします。
    株コードを追加します。
    StockWatcherはエラーを消去し、価格と変動の更新を表示し続けます。

 次は何?

セキュリティとクロスサイトリクエスト

あなた自身のマッシュアップを実装する前に、クロスサイトでJSONデータをダウンロードすることは強力だが、セキュリティリスクもまた有るということを思い出して欲しい。あなたが対話するサーバはあなたのアプリケーション内で任意のJavaScriptコードを実行することが出来るので、サーバが完全に信頼出来るということを確かめてください。Security for GWT Applicationsを読むために時間を割いてください。GWTアプリケーションに対する潜在的脅威とそれらとどう戦うかを説明してます。

中山道をちょっと歩いた

android用の神経衰弱ゲームを公開しました(・∀・)
The Match-up(Memory) game for android was released!

Google Play:
Mole's Match-up.

Introduction page:
Mole’s Match-upをリリースした∩( ・ω・)∩


埼玉の方で夜間の作業があり、徹夜明けの状態で中山道をちょっと歩いてみた(ノ∀`)

(さらに…)

うぶんちゅ坂(10)

android用の神経衰弱ゲームを公開しました(・∀・)
The Match-up(Memory) game for android was released!

Google Play:
Mole's Match-up.

Introduction page:
Mole’s Match-upをリリースした∩( ・ω・)∩


NTFSフォーマットのHDDを自動マウントさせる

そういえば、ntfsのデータディスクがオートマウントされずに
毎回nautilusで触ることによってマウントしてることに気づく。
自動マウントさせる方法はどうすんだべか(・∀・)?

(さらに…)