Resource Script
今回からはResource Scriptについてです。Live Frameworkはリソース指向のプログラミングモデルを提供しており、すべてのものをリソースとして扱います。これまで本連載ではMesh Objectなどのリソースが登場しました。今回のResource Scriptもそれらと同等なリソースのひとつです。特徴はその名の通りスクリプトとして実行が可能なことがいえるでしょう。Resource Scriptを使用すると複数のリソース操作と、それぞれの操作の順次処理や分岐処理などの制御構造をひとつのリソースとして表すことが可能です。またそれだけでなくリソースの追加や更新などをトリガーとしたバッチ処理も可能です。今回はResource Scriptの文法の種類と実行までを紹介します。
Live Frameworkのリソースモデル(図1 )を見てみましょう。これまで本連載ではMesh以下のリソースを扱っていました。ProfilesやContactsは連載の内容として直接は扱っていませんが、ユーザー情報に関する部分はここに含まれています。Scriptsはそれらと同階層に位置づけられたリソースのひとつです。ただし単独で使うということは基本的になく、ほかのリソースを操作しますので今回もMesh以下のリソースが出てきます。リソースの操作は、一般的にCRUDと呼ばれる生成(Create) 、読み取り(Read) 、更新(Update) 、削除(Delete)の4種類です。これに加えてデータ同期の操作があります。
図1 リソースモデル
※MeshはリソースのひとつではなくMesh階層下にMesh Objectなどのリソース群があります。
使用する3つの利点
Resource Scriptは、ほかのリソースに対する操作の集合と考えることができます。これはResource Scriptを使用しなくても、プログラミング言語で同等のリソース操作を行えばResource Scriptを作成する必要はないとも言えます。では、Resource Scriptを使用する利点は何があるのでしょうか。
処理の抽象化
まず操作の集合による利点です。Live Frameworkを利用しLiveサービス上の各リソースへアクセスする際、Live Operating EnvironmentとHTTPによる通信を行います。このとき行う操作単位は、リソースの作成・読み取り・更新など基本的なものに限られています。例えばMeshサービス上にファイルをコピーする場合、ファイルが既に存在しているかの確認(読み取り) 、存在している場合は削除、そしてファイルの作成というように複数の操作が必要です。Resource Scriptを用いると意味のある処理をひとつのリソースとして表現が可能です。
パフォーマンス改善
上記のように通常は多くのHTTPアクセスがアプリケーションとLive Operating Environmentとの間で必要になります。Resource Scriptの処理内容はサーバーサイドでの実行が可能で、このときアプリケーションとLive Operating Environment間のHTTPアクセスは1回に集約されます。このように複数のHTTPアクセスをまとめ、アプリケーションの動作改善にも使用できます。
アプリケーションの拡張
Resource Scriptは、リソースが作成・更新・削除される前または後をトリガーとして実行することが可能です。これは既にあるアプリケーションのロジックの変更や拡張として使用できることを意味します。トリガーによる実行もResource Scriptの大きな特徴のひとつです。
文法
Resource Scriptは、順次処理や条件分岐、繰り返処理などを記述可能でプログラミング言語の性質を持っています。Live Frameworkのリソース操作向けの言語であり、このような特定分野用に設計された言語をドメイン固有言語と呼びます。Resource Scriptもそのひとつです。言語となるとその文法も存在します。ここではResource Scriptの文法の内容をみてみましょう。
文法は、次の3種類を記述するものに大きく分けることができます。
そして、Resource Scriptのプログラム文法はStatement という記述単位で構成されています。Statementの組み合わせをStatement DOMと呼び、これをコンパイルすることで実行可能なResource Scriptを得ます(図2 ) 。
図2 Statement DOMとResource Script
コンパイルできる点もこれまで登場したLive Frameworkのリソースと大きく異なりますね。まずは、Statementを確認しておきましょう。
Statementは、Live Framework SDKにある.NET FrameworkまたはSilverlight用のライブラリではMicrosoft.LiveFX.ResourceModel.Scripting.Statementクラスとして用意されています。Resource ScriptやStatement自体は特定のプログラミング言語に依存するものではありませんが、本連載ではLive Framework SDKの.NET Framework用ライブラリのクラスとC#のコードをまじえて紹介します。
リソース操作
最初にリソース操作についてです。本記事ではリソース操作という言葉を使用しましたが、Live Frameworkの文書ではWeb Operation StatementとSynchronization Statementsと分類されています。それぞれWeb上のリソース編集のためのAtom出版プロトコルと、AtomまたはRSSを使用したデータ同期に関する仕様のFeedSyncの内容を反映したものです。
Web Operation StatementおよびSynchronization Statementsは、Statementクラスの静的メソッドを呼び出して生成することができます。たとえばリソースを作成する場合は、Statement. CreateResource<TResource>メソッドを使用します。
以下にC#のコードを示します。Mesh Objectを作成するStatementオブジェクト(CreateResourceStatementオブジェクト)を生成しています。
var statement = Statement . CreateResource < MeshObjectResource >(
"createMeshObjectStatement" ,
new Uri ( "https://user-ctp.windows.net/V0.1/Mesh/MeshObjects" ),
new MeshObjectResource ( "My Mesh Object" ));
引数など詳しい内容について今回は言及していません。実際に試してみたい方はVisual C#のコンソールアプリケーションプロジェクトを作成しコードを記述してみてください。Live Framework SDKの.NET Kitライブラリに加え、System.ServiceModelとSystemServiceModel.Webの参照も追加してください。
CreateResourceStatement以外にも次のクラスなどが用意されています。
CreateMediaResourceStatement
ReadResourceStatement
ReadMediaResourceStatement
ReadResourceCollectionStatement
UpdateResourceStatement
DeleteResourceStatement
Create、Read、Update、Deleteなど名前からどのような操作かわかりますね。これらの操作は実際にStatementが実行される際、Live Operating Environmentに対してのHTTP POST、GET、PUT、DELETEメソッドに置き換えられます。
データ同期に関するStatementは、SynchronizeResourceCollectionStatementが用意されています。
制御構造
制御構造のStatementを使用すると順次や条件分岐などを表現可能です。制御構造用のStatementは、クラスライブラリではCompoundStatementクラスを継承したクラスになります。現在のLive Frameworkでは、以下のクラスが用意されています。
SequenceStatement
InterleaveStatement
ConditionalStatement
LoopStatement
SequenceStatementは、順次を表すStatementです。次の例ではMesh Objectを順番にふたつ作成することを記述したStatementになります。Statement.Sequenceメソッドは、SequenceStatementを返します。
var sequence = Statement . Sequence
(
Statement . CreateResource < MeshObjectResource >(
"createMeshObjectStatement1" ,
new Uri ( "https://user-ctp.windows.net/V0.1/Mesh/MeshObjects" ),
new MeshObjectResource ( "My Mesh Object1" )),
Statement . CreateResource < MeshObjectResource >(
"createMeshObjectStatement2" ,
new Uri ( "https://user-ctp.windows.net/V0.1/Mesh/MeshObjects" ),
new MeshObjectResource ( "My Mesh Object2" ))
);
InterleaveStatementは、複数のStatementすべてが処理完了するまで待機するStatementです。ConditionalStatementは条件分岐、LoopStatementは繰り返しを表現できます。
データフロー
最後はデータフローです。ここでのデータフローとは、データの相互関係の記述についてです。StatementBinding というクラスを用いてStatementとStatementの関係を記述可能です。関係付けることによってStatementの実行結果を次のStatementで使用などの処理が可能になります。
例えば、フォルダを作成してその中にファイルを作成したい場合、どちらもCreateResourceStatementによりリソース作成のStatementを記述できますが、ファイルは作成したフォルダの中に配置しないといけません。このような関連情報をStatementに含める場合にStatementBindingを使用します。StatementBindingはStatementではなく、Statementへ指定できるパラメータのひとつになります。
フォルダ内にファイルを作るコードを示します。フォルダ内のファイルと表現しましたが、MeshサービスのLiveフォルダはMesh Objectリソースの一種です。Mesh ObjectはData Feedリソースのコレクションを持ち、ひとつのData Feedリソースの中にファイルとなるData Entryリソースを持っていますので、その点にも注意してコードを見てください。
var folder = new MeshObjectResource ( "アルバム" );
folder . Type = "LiveMeshFolder" ;
var df = new DataFeedResource ();
df . Type = "LiveMeshFiles" ;
var s1 = Statement . CreateResource < MeshObjectResource >( "s1" , new Uri ( "https://user-ctp.windows.net/V0.1/Mesh/MeshObjects" ), folder );
var s2 = Statement . CreateResource < DataFeedResource >( "s2" , null , df , Statement . Bind ( "CollectionUrl" , "s1" , "Response.DataFeedsLink" ));
var s3 = Statement . CreateMediaResource ( "s3" , null , new Uri ( "http://example.jp/foo.jpg" ), null , Statement . Bind ( "CollectionUrl" , "s2" , "Response.MediaResourcesLink" ));
var s4 = Statement . CreateMediaResource ( "s4" , null , new Uri ( "http://example.jp/bar.jpg" ), null , Statement . Bind ( "CollectionUrl" , "s2" , "Response.MediaResourcesLink" ));
var sequence = Statement . Sequence
(
s1 ,
s2 ,
Statement . Interleave
(
s3 ,
s4
)
);
上記コードは、結果的にLiveフォルダ内にふたつの画像を作成します。Data FeedのCreateStatementとCreateMediaResourceメソッドの引数にStatement.Bindメソッドの結果を指定しています。Statement.Bindの戻り値はStatementBindオブジェクトです。詳細な内容はさておき、文字列によりStatementを指定しているのがわかるかと思います。最後にこれらのStatementを組み合わせたSequenceStatementを作成しています。
コンパイルと実行
コンパイル
Statement DOMはコンパイルによってResource Scriptに変換することができます。文法の説明で使用したC#のコードをコンパイルするには次のようになります。StatementクラスはCompileメソッドを持っています。
var script = sequence . Compile ();
コンパイルによってひとつのリソースとすることができました。Resource Scriptは、リソースモデル上ではMesh ObjectやData Feedと同様にリソースの一種です。ただし、クラスライブラリではResourceクラスを継承しておらず、同じように扱うことはできません。
コンパイルによってできたResource Scriptは実行可能です。次は実行してみましょう。
サーバーサイド実行
Resource Scriptの実行はサーバーサイドでの実行とクライアントサイドでの実行に分類することができます。
サーバーサイドでの実行を図3 に示します。
図3 サーバーサイドでの実行
アプリケーションはLive Operating Environmentに対してResource Scriptを渡します。その内容はサーバー側で解釈され、すべての処理を終えた後、結果が返ってきます。
より具体的には、Resource ScriptはXMLやJSON形式にシリアライズ化されています。これをHTTP POSTメソッドによりLOEへ渡します。レスポンスも同様にシリアラズされたものを受信しています。
サーバーサイド実行の特徴は、複数のStatementからなるScriptが1回のHTTP POSTメソッドアクセスで済むことです。
コードでは次のように記述します。実行には認証情報を渡す必要があります。
script . RunAtServer ( new NetworkCredential ( "user@example.jp" , "password" , "https://user-ctp.windows.net/V0.1/Script" ));
クライアントサイド実行
クライアントサイドでの実行も可能です。その内容を図4 に示します。
図4 クライアントサイドでの実行
クライアントサイドで実行した場合、RunAtServerメソッドの代わりにRunメソッドを使用します。
script . Run ( new NetworkCredential ( "user@example.jp" , "password" , "https://user-ctp.windows.net/V0.1/Script" ));
図4 に示すように、クライアントサイドで実行するとResource Scriptの内容はアプリケーション側で解釈され最初の処理単位に分割し、Live Operating Environmentへ渡されます。この場合、サーバーサイド実行のようにLive Operating Environmentとの対話回数を減らすというアプリケーションの改善はできません。ただし、ある一連の処理をResource Scriptという単位に抽象化したコードの記述可能という利点はありますね。
また、少しサーバーサイド実行でふれたようにResource ScriptはXMLやJSON形式にシリアライズ可能です。これらのファイルを読み取りクライアントサイドで実行ということも可能です。シリアライズ化については次回紹介する予定です。
今回は以上です。少し駆け足でしたが、Resource Scriptの概要はつかめていただけたでしょうか。次回はより詳しい内容やより多くのサンプルコードを紹介する予定です。