2011年10月30日日曜日

objectのjsonデータを変換する。

Google+のAPIの戻り値に"object"というオブジェクトデータがあり、
これがC#の予約後に引っかかってしまい、NewtonsoftのJSONパーサで解析をしていると無理になります。

https://developers.google.com/+/api/latest/activities#resource

なので

            private ObjectData objectValue;
            [Newtonsoft.Json.JsonPropertyAttribute("object")]
            public virtual ObjectData Object
            {
                get
                {
                    return this.objectValue;
                }
                set
                {
                    this.objectValue = value;
                }
            }
とすればOKです。

2011年10月28日金曜日

WindowsPhoneで最初の画面を選ぶ

OAuth認証は基本的に最初の一回でOKのはずです。
なのでアクセストークン(もしくはリフレッシュトークン)を持っていて
通信可能な状態だった場合、別の画面を表示する必要があります。

画面を作る
まず縦向きのページを作成します。
分岐を作成する
App.xamlに対して、Startupイベントを指定します。
<Application 
    x:Class="Ziro.PlusPhone.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    Startup="Application_Startup">
で、App.xzml.csにコードができるので
        private void Application_Startup(object sender, StartupEventArgs e)
        {
            if (oauth.Load())
            {
                RootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
            }
            else
            {
                RootFrame.Navigate(new Uri("/LoginPage.xaml", UriKind.Relative));
            }
        }
という風に条件式を作ってあげて、遷移先を変更してあげます。 私の場合、OAuth認証があるかどうかで判断しています。
デフォルトの画面を読み込ませない
次にプロジェクトの「Properties」内にあるWMAppManifest.xmlの TasksタグにあるDefaultTaskのNavigationPageを削除します。
    <Tasks>
      <DefaultTask Name="_default" NavigationPage="/MainPage.xaml"/>
    </Tasks>
↓
    <Tasks>
      <DefaultTask Name="_default"/>
    </Tasks>
これをやっておかないと強制的にここが優先されます。 これでOKです。

2011年10月27日木曜日

非同期で結果を受け取る

WindowsPhoneの非同期処理の理念は伝わっているけど、、、
C#の言語理解が足りないから実装方法がわからない。
GoogleのAPIの実装を見た時に「うわっこんな実装になるのか。。。なんで?」って
ところが理解できてなかったと再度思うことになった。
何がしたいか?
WindowsPhoneでGoogle+にアクセスしたい。
そこで処理を書いていくと

1.OAuthの部分(+その後の処理)をGUIと切り離したいのでライブラリ化しておきたい。
 -だけどアクセスは非同期処理になるので、データが返ってくるタイミングがわからない。
2.なのでそのデータをどう使うかはPhone側関数の処理にしたい。
3.その関数の引数はJsonの生データ(string)ではなくて、型が決まった状態で受け取りたい。
 -Newtonsoft.JsonのDeserializeObject()を呼び出すのでT型で呼び出したい。

この位の知識で実装してたら、あれ?あれ?って感じになったのでまとめておく。
レスポンスデータ取得後の呼び出し
最終的にT型で関数を呼び出すという目標に対して、
レスポンスが受けとったデータを呼び出すので
        public IJsonResult target;

        string = {レスポンスデータ};
        target.SendJson(data);
みたいな実装が必要なのでまずインターフェースを定義してみた。
これは生成時にT型が必要なのですが、呼び出し時にtargetをインスタンス化する為です。
SendJson()の実装
で、SendJson()の実装はジェネリックを利用して
    public class JsonResult<T> : Ziro.OAuth.IJsonResult where T : JsonData 
    {
        private Action<T> action;
        public JsonResult(Action<T> lambda )
        {
            action = lambda;
        }
        
        public void SendJson(string responseData) {
            //データを解析
            T jsonData = JsonConvert.DeserializeObject<T>(responseData);
            action(jsonData);
        }
    }
として、文字列をT型でデシリアイズして、それを引数にaction()を呼び出しています。
action()は引数がT型のラムダ式を引数に持つ式をコンストラクタで受け取ってます。
リクエストの呼び出し
        private void GetMe()
        {
            oauth.target = new JsonResult<GooglePlusData.Person>(GetPeople);
            oauth.GetPeople("me");
        }

        private void GetPeople(GooglePlusData.Person person)
        {
            //元のスレッドでメイン画面に遷移
            this.Dispatcher.BeginInvoke(() => NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative)));
        }
って感じでOKです。
GetPeple()はUrlを作成して、GETしています。

これでJsonResultの生成時に型情報と受け取りの実装を渡します。
総括
一瞬、OAuthを直接行う部分のインスタンス化を行う時にT型を使おうとしたのですが、
アクセストークンをやり取りするのがだるかったのでこうしています。
※おそらく後で分散ストレージを使うので、そうしなくても良かったかな?とも思ってます。
こうしておくことで多分他のOAuthを作りたい感じになった時に楽になるかな。。。と勝手に思ってます。

ここに行くまでブヒーって感じでした。
C#の知識が乏しい状況での実装なので、本当にこれでいいのかも不明です。


JavaScript辺りのゆるふわな感じと、Javaの静的な感じが実現できていて素晴らしいなぁ。
結論としては、、、λカワイイ。。。

2011年10月26日水曜日

WindowsPhoneでGoogle+に対してOAuth認証

Google+APIでの認可を書いて、
後日WindowsPhoneへの移植を試みた。。。


しかしそれと同時に衝撃の事実。
DLLの参照設定ができないのだ。



「WindowsPhoneアセンブリのみと連動・・・」・・・なんとっ!

ということでOAuthの生コードを書くことにした。
何か調べるとライブラリは存在するのだが、OAuth1.0っぽいもの(Twitter系)が多くて
勝手に使い物にならないと判断した。

まぁC#触るの自体久しぶりだし、言語になれる意味でやっていきますか。
ってことで結局Google+のOAuthのページを読むことにした。

画面を作ります。

OAuthにはブラウザアクセスが必要なので、ブラウザを準備して
作成した認証コードが必要になるのでテキストと認証用のボタンを準備しておきます。

認証用のURLの発行

上記のURLにある通りにアクセスするURLを作成します。

https://accounts.google.com/o/oauth2/auth?
  client_id=xxxxxxx.apps.googleusercontent.com&
  redirect_uri=urn:ietf:wg:oauth:2.0:oob&
  scope=https://www.googleapis.com/auth/plus.me&
  response_type=code

自分のクライアントIDを添えてブラウザでアクセスします。
scopeに関しては上記のOAuthのサイトでは、別のスコープになってますので注意してください。

これを画面の初期化時にブラウザに設定して呼び出します。
※もちろん本物のアプリは違うタイミングでしょうけど。




こういう風にGoogleの認証ページになります。
認証は前にやった時と同じように行います。で認可が下りると
AuthCodeが発行された画面になります。


アクセストークンを取得する

AuthCodeコードがブラウザ画面に出ますので下にあるテキストボックスに貼付け
「認証」ボタンを押したところで


https://accounts.google.com/o/oauth2/token

のURLに対して

POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded

client_id=xxxxxxxxx.apps.googleusercontent.com&
client_secret=xxxxxxxxxxx&
code={AuthCode}&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
grant_type=authorization_code

というポストを書いてあげます。
「code」は認証した後に発行された認証コードをテキストボックスに設定した値になります。

ここでWindowsPhoneは非同期処理しかないので送信には
BeginGetResponse(),BeginGetResponse()などを利用する必要があります。

これにより


{
  "access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
  "expires_in":3920,
  "token_type":"Bearer",
  "refresh_token":"1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ"
}

というような文字列が取得できます。
これらの解析にはNewtonsoft.Json.Silverlightを使用しました。


Google+にアクセスする。

さてアクセストークンができたので何はともあれアクセスです。


https://www.googleapis.com/plus/v1/people/me?access_token=xxxxxx


とアクセスしてあげたら自分の情報が取れます。
※meは自分の情報ってことなのでAPI的にはuserIdを指定してあげればOKです。

これでまたJsonが戻ってきますので、解析してあげたらOKなわけです。
OAuth2.0ですので、アクセストークンの時間が切れた場合は
refresh_tokenで再発行を行う必要があります。

その際はアクセストークン時に使用した引数を

refresh_token=1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ&
grant_type=refresh_token


と変えて再発行すれば再認可は必要なくなります。
※refresh_tokenも期限はあるみたいです。




総括


基本的にはOAuthの説明です。
やったことある方なら通常のGoogleのドキュメントだけでOKだと思います。


詳しいAPIの説明は
https://developers.google.com/+/api/
にあります。


注意すべきは
・現状ではGoogleのクライアントAPIでは、WindowsPhoneアプリは無理なこと。
・WindowsPhoneの非同期等のポリシーなどでWebアクセスが通常ではないこと。
・C#が結構イケテル事。
・API呼び出しはBearerを利用した方がいいと思います。
・更新系のGoogle+APIがまだ

WindowsPhoneとC#になれる時間もいるのでゆっくりクライアントを作っていく予定。

さて、ではWindowsPhoneアプリの開発ですね。

2011年10月23日日曜日

.NET(C#) でGoogleOAuthを行なってみる。


IS12Tを手にいれたけど、何かアプリつくろう!って思って考えてたら
Google+のクライアントがないことに気づいたのでそれを作ってみようと思う。


サンプルを読み込む


とにかくOAuthアクセスを実現する必要があるはずなので
まずはサンプルを取得してきます。

https://developers.google.com/+/downloads
http://code.google.com/p/google-api-dotnet-client/





ここにサンプルとあるのでそれを取得。
※各種OAuthとかの文章ありますけど、ソースとかが古かったりですね。

「Tasks.SimpleOAuth2」というプロジェクトがコンソールでできるやつみたいなので
そちらをスタートプロジェクトにして実行するわけですけど、
「Google.Apis.Samples.TasksOAuth2.ClientCredentials」に
APIキーの設定のがあるの以下のように設定します。




        public static readonly string ClientID = "xxxxxxxx.apps.googleusercontent.com";

        /// <summary>
        /// The OAuth2.0 Client secret of your project.
        /// </summary>
        public static readonly string ClientSecret = "xxxxxxxxxxxxxxxxlOd2y";

        /// <summary>
        /// Your Api/Developer key.
        /// </summary>
        public static readonly string ApiKey = "urn:xxxxxxxxxx";





OAuth用の準備


https://code.google.com/apis/console

に行ってGoogle+APIをONにしておきます。




今は「Courtesy limit: 1,000 queries/day」なので
1日1000回のアクセスまでのようですね。。。。ん?ユーザじゃなくてAPIキーでかな?

API AccessのところにOAuth2.0があるのでそこでキーを発行します。
OAuthでお馴染みのClientIDとSecretですね。






Google PlusのAPIを使ってみる

このサンプルはTasks APIの
PlusのDLLはBinaryサンプルのServiceの中にあります。
これを参照設定して追加してPlusServiceを使えるようにしておきます。



            // Display the header and initialize the sample.
            CommandLine.EnableExceptionHandling();
            CommandLine.DisplayGoogleSampleHeader("Google+ API");

コンソールにGoogleのロゴを出す部分ですね。特に大事なコードではないです。
一応TaskになっていたのでGoogle+に変更。



            // Register the authenticator.
            var provider = new NativeApplicationClient(GoogleAuthenticationServer.Description);
            provider.ClientIdentifier = ClientCredentials.ClientID;
            provider.ClientSecret = ClientCredentials.ClientSecret;
            var auth = new OAuth2Authenticator<NativeApplicationClient>(provider, GetAuthorization);


ここでClientIDとSecretを使ってURLを作成している処理です。
GetAuthrorizarionは、サンプルであるProgram.csにあります。



        private static IAuthorizationState GetAuthorization(NativeApplicationClient arg)
        {
            // Get the auth URL:
            IAuthorizationState state = new AuthorizationState(new[] { PlusService.Scopes.PlusMe.GetStringValue() });
            state.Callback = new Uri(NativeApplicationClient.OutOfBandCallbackUrl);
            Uri authUri = arg.RequestUserAuthorization(state);

            // Request authorization from the user (by opening a browser window):
            Process.Start(authUri.ToString());
            Console.Write("  Authorization Code: ");
            string authCode = Console.ReadLine();
            Console.WriteLine();

            // Retrieve the access token by using the authorization code:
            return arg.ProcessUserAuthorization(authCode, state);
        }





NativeApplicationClient を元にOAuthにアクセスするURLを作成していきます。
IAuthorizarionStateでTasksのGetStringValue()を読んでいるのでPlusServiceにしてあげます。
実行するとこんな感じです。


ReadLine()でOAuthの認証コードを待ち受けます。
※実際の実行タイミングはFetch()するまでアクセスはされません。

Process.Start()で作成したURLにアクセスしますのでこれと同時にブラウザが立ちあがってるはずです。


アクセスを許可するとキーが発行されるのでそれをコンソールにコピペして、Enterします。
タスクに対して





            var service = new PlusService(auth);
            Person me = service.People.Get("me").Fetch();
            CommandLine.WriteLine("     ^2" + me.Name);

            ActivitiesResource.Collection collection = new ActivitiesResource.Collection();
            ActivityFeed feed = service.Activities.List("me",collection).Fetch();
            foreach (Activity list in feed.Items)
            {
                CommandLine.WriteLine("     ^2" + list.Title);
            }
            CommandLine.PressAnyKeyToExit();




と行なってみたら、自分の投稿を取得できました。
はじめ自分のIDを指定して検索してたんですが
「うんなもんOAuthじゃねーヽ(`Д´)ノプンプン」だったんですけど"me"で取得できました。

一旦これでアクセス自体はできたみたいですね。

途中、OAuthとGoogle+のAPIと.NETのAPIを読んでいてパニック起こしました。
誰がどれを作っているのかわからなくなったからです。

上位のクラスとか結構しっかり作ってある感じなので
簡単にOAuth(Google+API)にアクセスすることができます。

これをネタにWindowsPhoneクライアントを作るっていう大きな作業が待ってます。

2011年10月12日水曜日

Jenkinsを利用したJSUnitの実行

普段、Java周りではJenkinsを利用していますが、
静岡ITPro勉強会インフラ部でBTS周りをやる事になったので、
CIの発表としてJenkinsの利用方法をやる事になりました。

通常Javaでテスト作ってMavenで構成して、SVNでつなげるというパターンが多いのですが
勉強会で発表する事もあり(Java屋さんがいない)少しいつもと違う環境で動作させる事にしました。
という事でJavaScriptのプロジェクトを準備して、GitHubに連携って方法を行なってみる事にしました。

継続的インテグレーションの意義


Jenkinsはソース管理システムからソースコードを引っ張ってきて、テストを実行してレポートをする。
というのが王道の使い方です。
これを常時繰り返す事で、常にソースコードはテストを常に実行され、健全な状態に保って行く事が可能です。
Cronみたいなイメージでも使用できますが、レポート等も取れ、可視化できるので
インフラ周りでも使う事は可能だと思います。

開発の現場(出先など)で苦労する点としては
・ビルドサーバを準備できない
・そもそもテストが自動化できてない><。
等と苦労する点があります。

管理者自身を助ける(単体テストの可視化と報告)優秀なやつなのですが
案外管理者等に伝わらない事が問題だと思っています。
※まぁこれは私のちから不足なのですが。

インストール


通常私の開発環境周りではTomcatが多いのですが、
軽いほうがいいかな?っと思い、軽量なコンテナのJettyを採用してみました。

ここからダウンロードしてきます。
ポート変更はetc/jetty.xmlでport(デフォは8080)の部分を変更すれば可能です。

「java -jar start.jar」
※ポートを開ける権限が無ければsudo等で実行してください

でサーバは起動します。
Jenkinsをダウンロードしてきます。

war形式で配布されています。※一瞬インストーラーになってたので焦った><。
「jankins.war」をJettyの「webapps」ディレクトリに展開すると

「http://localhost:8080/jenkins/」で起動画面をみる事ができます。

ジョブ


ジョブを作ります。
通常はMavenを使って構成しているのですが、その辺りに詳しくないとわかりづらいと思ったので
やはりここはフリースタイルで行なってみる事にした。

JSUnitでテストを出きるようにする


Javaのテストは良く書いていますが、JSUnitでテストをするのは初でした。
なのでまずJSUnitを準備してテストできる状況にします。

http://sourceforge.net/projects/jsunit/files/jsunit/2.2/

解凍を行ったら
app,css,images,java,build.xml,testRunner.html
をプロジェクトに置きます。
Javaは通常実行時には要らないのですが、JenkinsでJSUnitプラグインを利用する際に指定するので必要です、
build.xmlはserver.xml等と名前を変えておきます。
※後述するビルドを「build.xml」とする為で、どちらも任意の名前で良い。
配置するディレクトリは「jsunit」とか「test」とかで良いと思います。

<script language="JavaScript" type="text/javascript">

/**
* テストの一覧
*/
function suite() {
var suite = new top.jsUnitTestSuite();
suite.addTestPage('testDesigner.html');
return suite;
}

</script>


というSuiteを用意して増えた時でも大丈夫な状態にしておきます。

<script language="JavaScript" type="text/javascript">
// テスト用のコード
function testMethod() {
assertEquals($('.item').length,3);
assertNotNull($('.content-box'));
}
</script>


というテストメソッドを作っておきます。他のxUnitと同じ感じですね。

でファイルシステムでも良いので「testRunner.html」にアクセスします。



testRunner.htmlからファイルを指定してRunするとこのようにテスト結果が出力されます。

これでテストする準備は整った。

プラグインを入れよう!


普段使っている時でもJenkinsのプラグインには様々なものがあります。
ソース管理はほとんどサポートしていますし、CheckStyle等のコードチェッカー等も充実しています。

今回はGitHub(+Git)とJSUnit(+xUnit)のプラグインを入れます。

ソースを取ってこよう!


ジョブの設定画面で「ソースコード管理システム」で「Git」を選択します。
そこにGitHubにあるリポジトリを指定しておきます。



この時点でビルドすると「ワークスペース」にソースを持ってこれるはずなので
それを確認しておくのが良いでしょう。こんな感じです。




ビルドを設定してテストしよう!


テストを実行する為、ビルドはAntを呼び出します。
Ant呼び出しを設定して、testをターゲットにしておきます。
Antの実行パス等はJenkins自体の設定で指定できます。



ビルドファイルなのですがリポジトリ等に置いてあるAntの設定ファイルを叩きます。
「./{projectName}/test/build.xml」
とかになると思います。

build.xmlは以下※展開してください。

<?xml version="1.0" encoding="utf-8"?>

<project name="JSUnitForJenkins" default="test" basedir=".">
<description>
Jenkins 上で JSUnit によるユニットテストを行う。
</description>
<property environment="jenkins"/>

<!-- プロジェクトのホームディレクトリ -->
<property name="home"
location="${jenkins.WORKSPACE}/drag-designer"/>
<!-- テスト対象のページ -->
<property name="testPage"
location="${home}/test/testSuite.html"/>
<!-- JSUnit の動作するポート番号 -->
<property name="jsunitPort"
value="8090"/>
<!-- Firefox のパス -->
<property name="firefox"
location="/Applications/FireFox.app/Contents/MacOS/firefox"/>
<!-- JSUnit のホームディレクトリ -->
<property name="jsunitHome"
location="${home}/test"/>
<!-- ログを出力するディレクトリ -->
<property name="logsDirectory"
location="${home}/test/logs"/>
<!-- JSUnit 形式のログファイルを JUnit 形式のログファイルに変換する XSLT -->

<!-- TestRunner -->
<property name="testRunner"
location="${jsunitHome}/testRunner.html"/>
<!-- JSUnit Server を起動する build.xml -->
<property name="buildScript"
location="${jsunitHome}/server.xml"/>

<target name="test">
<mkdir dir="${logsDirectory}"/>
<delete includeemptydirs="true">
<fileset dir="${logsDirectory}" includes="**/*"/>
</delete>
<makeurl file="${testRunner}" property="testRunnerURL"/>
<ant antfile="${buildScript}" dir="${jsunitHome}" target="standalone_test">
<property name="browserFileNames" value="${firefox}"/>
<property name="port" value="${jsunitPort}"/>
<property name="logsdirectory" location="${logsDirectory}"/>
<property name="url" value="${testRunnerURL}?testPage=${testPage}"/>
</ant>

</target>
</project>


プロジェクトのホームを設定して対応のSuiteのページを設定。
ブラウザを指定、ログ出力(テスト結果)の箇所、TestRunnerの指定、
JSUnitをコピーした際に名前を変更しておいてserver.xmlを指定します。

この設定でJenkinsはワークスペース上に取ってきたソースを元にJSUnitの実行を行います。
途中Firefoxで実行していますが
これらを増やして、クロスブラウジング等のテストを行うのも可能です。


処理結果をリポートする


Build後の処理として
「Publish testing tools result report」を選択して
JSUnit-2.2を選択して追加します。

**{projectName}/test/logs/*.xml

と、ビルドした際のテスト結果を出力した位置を指定します。これでOKです。



ジョブ実行


これで準備完了ですのでジョブを実行します。
実行時にFirefoxが起動してびっくりしますけど><。

で結果がこれ。



テスト自体はしょぼいですけど、できましたー

問題


・クロスブラウジングのテスト何かもできるなぁ〜と思っていたのですが
 通常動作しているJenkinsサーバはXがないけど動作するのかな?

・今回Firefox使いましたけど、バージョンアップとかの画面出てしまうと
 テスト自体ストップする状況になってしまうような気がする


おまけ


・本当はMylynとGitHubをつなげたIssue管理をやろうとしたのですが
 それは後日ブログに書きます。
・私個人としてはCIでパトランプを回すのが目標なのですが
 後日の勉強会でやった事ある方にパトランプを回す所を見せてもらいました!

パトランプの動画

やってみて、興味を示してくれた方が何人かいらっしゃって
既に実行された方もいるみたいなので、やって良かった!と思いました。
※パトランプの成果が一番大きいかも><。