Delphi Labs: DataSnap XE - WebBroker jQueryMobile ボイラープレート

By: Chikako Yonezawa

Abstract: このチュートリアルでは、Web ブラウザに jQuery ボイラーテンプレートを 返却するスタンドアロン Web アプリケーションを構築するために Delphi XE WebBroker フレームワークを使用します。

    若干の免責事項

“Delphi Labs” では、Delphi での開発にフォーカスしていますが、ここで説明されているアプリケーションのすべては、RAD Studio の一部である C++Builder でも構築可能です。

Delphi と C++Builder は、とても密接に統合されています。双方は、同一の基盤である統合開発環境 (IDE: Integrated Development Environment) 上の異なる「パーソナリティ」であり、VCL (Visual Component Library) を共有しています。

Delphi Pascal プログラミング言語を使用するのは、私個人の好みです。C++ をより好む方は、C++Builder XE (http://www.embarcadero.com/jp/products/cbuilder) でお試し下さい!

    はじめに

このラボでは、jQuery Mobile JavaScript ライブラリ を使い DataSnap サーバーからデータベースのデータを読み込んで表示するための Web アプリケーションの構築を Delphi XE を使用して行います。

JavaScriptだけで行うコーディングはとても煩雑ですが、その作業を簡単に行えるようにするための多くのフレームワークとライブラリがあります。最も人気のある JavaScript ライブラリの 1つに、「迅速で簡潔」かつ「迅速な Web 開発のために、HTML ドキュメントのトラバース、イベント処理、アニメーション、Ajaxによるやり取りを単純化」する jQuery (http://jquery.com/) があります。

jQuery の世界での最も新しいプロジェクトのひとつに、iPhoneや、Android や、その他のスマートフォン上で利用可能な Web ブラウザ用に最適化された、その人気のライブラリ jQuery の “mobile” バージョンがあります。この “mobile” なルックアンドフィールをもつ Web ページを構築するための HTML5 や CSS3 のような最新の Web 標準を使用する jQuery コアの一番上のレイヤーです。

この記事を書いている時点での jQuery Mobile は、開発のアルファ段階のため、本日 (2011年3月) に使用可能な機能が、最終的なリリースと異なる可能性があります。

この記事では、http://jquerymobile.com/demos/1.0a3/ で公開されている jQuery Mobile Alpha 3 リリースを使用します。

この 2つのパートのチュートリアルの最終的な目的は、基となる InterBase XE の “Employees” サンプルデータベースからデータを供給する Delphi XE DataSnap スタンドアロンデータサーバーと、データを表示するために、jQuery Mobile を使用して WebBroker Delphi XE スタンドアロン Web アプリケーションであるクライアントから構成される、多層かつスケーラブルなサンプルの DataSnap システムを構築することです。

Hide image
Click to see full-sized image

expand view>>

    WebBroker を理解する

Delphi で構築できるアプリケーションには様々な形式があります。多くの開発者にとって、Delphi は、高速で洗練されたユーザーインターフェースを用いて高機能な Windows クライアントを構築することを意味します。Delphi で記述されたそのような強力なアプリケーションの最も良い例の一つとして、人気の通信ツール “Skype” があります。Delphi で Web アプリケーションを構築できることを知っているプログラマはそれほど多くありません。Delphi および C++Builder で Web アプリケーションを構築するための VCL フレームワークは、WebBroker と呼ばれます。

DLL (IIS のような Web サーバーへ配布することが可能) として Web アプリケーションを構築することに加えて、Delphi XE は、Web サーバーと Web アプリケーションの両方の機能を内蔵する Windows 実行可能ファイルであるスタンドアロン Web アプリケーションを、全く新しい形式として導入しました。

これは、その Web サーバーが Delphi の “Indy” コンポーネントを使用して実装されているので、非公式に “Indy WebBroker” と呼ばれています。

Delphi は、さまざまな種類の Web アプリケーションを構築するためにいくつかのウィザードを提供します。最も基本的な Web アプリケーションは、 “Web Server アプリケーション” ウィザードを使用して作成することができます。他にももっと専門的なウィザードがあります – 前 Delphi のプロダクトマネージャーである Nick Hodges の言葉 - 「スクラッチでも行えるが、より改善された出発地点を提供する」ウィザードです。例えば、伝統的な SOAP Web サービスを作成するための Delphi の “SOAP Server アプリケーション” ウィザードを使うことができますし、また、JavaScript クライアントを統合した Web ベースの DataSnap サーバーを作成するための “DataSnap REST アプリケーション” ウィザードを使うこともできます。技術的には、空の WebBroker の “Web サーバーアプリケーション” から始め、それを SOAP や REST の Web アプリケーションにするために必要なすべてのコンポーネントやコードを追加します。専用のウィザードを使うことは非常に便利です。結局のところはこれが、物事を単純化するという “ウィザード” の考え方全体なのです!

IDE のメニューより [ファイル|新規作成|その他] を選択し、「新規作成」ダイアログの [Delphi プロジェクト| WebBroker] カテゴリ内の “Web サーバーアプリケーション” アイコンをダブルクリックします。

Hide image
Click to see full-sized image

expand view>>

Web サーバーアプリケーションの形式として、 “Indy VCL アプリケーション” を選択し、[OK]ボタンをクリックします。

Hide image
DataSnap91

空の “Indy WebBroker” Web アプリケーションが作成されます。

すべてを保存します。このプロジェクトのための以下の新しいディレクトリ “C:\DataSnapLabs\WebBroker_jQueryMobileBoilerplate” を作成します。1番目のユニットには “FormMainUnit”、2番目のユニットには、“WebModuleMainUnit”、全体のプロジェクトには “WebBrokerjQueryMobileBoilerplate” と命名します。

現時点で、プロジェクトマネージャーを見ると、このようになっています。

Hide image
DataSnap92

“FormMainUnit” は、Delphi XE の新しい Indy Web サーバーの実装を内蔵するアプリケーションのメインフォームクラスを含んでいます。“WebModuleMainUnit” は、“Webモジュールクラス” の実装を含んでいます。WebBroker Web モジュールクラスは、DataSnap サーバーメソッドクラスととてもよく似たふるまいをします。それらはプログラマによってインスタンス化されず、有効期間は、フレームワークによってコントロールされます。

プロジェクトオプションのためのプロジェクトオプションダイアログを表示するため、IDE のメニューから [プロジェクト|オプション] を選択し、ダイアログ内の “フォーム” カテゴリを選択します。

Hide image
Click to see full-sized image

expand view>>

アプリケーション内で自動生成されるフォームは “FormMain” だけで、“WebModuleMain” はコード内で生成される必要があります。

Delphi プロジェクト全体のソースを見れば、この Web アプリケーションの実装の有効期間の管理がどのようになっているのかがわかります。

IDE のメニューより [プロジェクト | ソース表示] を選択すると、以下のようなコードになっているはずです。

program WebBrokerjQueryMobileBoilerplate;

{$APPTYPE GUI}

uses
  Forms,
  WebReq,
  IdHTTPWebBrokerBridge,
  FormMainUnit in 'FormMainUnit.pas' {FormMain},
  WebModuleMainUnit in 'WebModuleMainUnit.pas' {WebModuleMain: TWebModule};

{$R *.res}

begin
  if WebRequestHandler <> nil then
    WebRequestHandler.WebModuleClass := WebModuleClass;
  Application.Initialize;
  Application.CreateForm(TFormMain, FormMain);
  Application.Run;
end.

この特定のアプリケーションで使用されている Web モジュールクラスの参照を保持しているグローバルな無名メソッドの変数があります。DataSnap の場合、用意されたさまざまな有効期間のオプションを用いて、複数の多層サーバークラスを持つことも可能です。WebBroker アーキテクチャはより単純で、ただ1つの Web モジュールクラス型を持つことしかできず、それらにはデフォルトの有効期間の管理オプションが1つあります。

“Ctrl” ボタンを押したまま、エディタ内の “WebRequestHandler” 識別子上にマウスカーソルを合わせると、それが定義されているコード内の実際の場所へのハイパーリンクが表示されるようにすぐに変化させることができます。

“WebRequestHandler” グローバル変数は、“TWebModuleClass” 型のプロパティを持つ Web ハンドラクラスのインスタンスを返す無名メソッドへの参照として定義されています。この設定は、事実上にクラスファクトリのデザインパターンを実装しています。Web アプリケーションのアプリケーションロジックは、完全に Web モジュールクラスの内部に実装されます。

Web モジュールクラスは、 “TDataModule” を間接的に継承しており、http コンテンツの生成とデータアクセスのための非ビジュアル化コンポーネントのコンテナとして使用できます。すべての Web モジュールは、“TWebActionItem” コンポーネントのコレクションである published な “Actions” プロパティを持っています。

Hide image
DataSnap94

“Web サーバーアプリケーション” ウィザードは、 “DefaultHandler” と呼ばれるデフォルトの Web アクションと、その “OnAction” イベントの実装を追加してくれました。

“Actions” プロパティの省略 […] ボタンをクリックすると、簡単に Web アクションを追加できる、このプロパティ用のコレクションエディタが表示されます。

Hide image
Click to see full-sized image

expand view>>

ウィザードは、また、“Web Server Application” という文字列を表示する HTML コードのかたまりを返す “OnAction” イベント用のイベントハンドラを生成します。これは、プログラマが Web クライアントへ返却するコンテンツを実装する場所です。このイベントは “Request: TWebRequest”, “Response: TWebResponse” ,“Handled: boolean” の 3つのパラメータを持っています。“Request” パラメータは、処理される HTTP リクエストについての全ての情報を含みます。2番目のパラメータは、Web サーバーアプリケーションから、クライアントへ返却されるすべてのデータをカプセル化する “Response” オブジェクトです。“Handled” の boolean パラメータは、リクエストが完全に処理されたかを示します。より一般的なシナリオでは、1つの HTTP リクエストが、複数の WebActionItems によって処理されることが可能になります。

“Response” オブジェクトのプロパティを設定することは、プログラマの作業となります。ウィザードは、”Response.Content” プロパティへアサインするためのコードを生成しました。デフォルトのコンテンツタイプは “text/html” ですが、例えば、イメージのような他のデータ型を返却するできこともできます。そのためには、適切な MIME “ContentType” を設定する必要があります。

“Actions” コレクション内のすべての “TWebActionItem” ごとに、HTTP リクエストの HTTP メソッドの型が何か、HTTP クライアントから送られた URL からの “PathInfo”が何かを設定することができます。

“OnAction” イベントを実装する代わりに、“WebActionItem” オブジェクトのコンテンツを提供するための “Producer” コンポーネントを使うことも可能です。

何か動的コンテンツを返却するために “OnAction” イベントのデフォルトの実装を変更しましょう。

以下は、 “WebModuleMainUnit” のコンテンツ全体です。

unit WebModuleMainUnit;

interface

uses
  SysUtils, Classes, HTTPApp;

type
  TWebModuleMain = class(TWebModule)
    procedure WebModuleMainDefaultHandlerAction(Sender: TObject;
      Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModuleClass: TComponentClass = TWebModuleMain;

implementation

{$R *.dfm}

procedure TWebModuleMain.WebModuleMainDefaultHandlerAction(Sender: TObject;
  Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
  Response.Content :=
    '<p>"Hello World" from <b>Delphi Labs</b> Delphi WebBroker test app!</p>'
  + '<p>The time at our server is <b>' + DateTimeToStr(Now) + '</b> right now.</p>'
  + '<p>HTTP response content type is: <b>' + Response.ContentType + '</b></p>';
end;

end.

ここで、Delphi WebBroker アプリケーションを実行すると、次のような出力が確認できるはずです。

Hide image
TestWebApp_output

    WebBroker jQueryMobile ボイラープレート

jQueryMobile の例をインターネットで見つけようとするなら、「ボイラープレート」と呼ばれるものをとても頻繁に見つけるでしょう。この URL: http://jquerymobile.com/demos/1.0a3/#docs/pages/page-template.html で、jQuery Mobile の実際のボイラープレート html ページのプレビューを行うことができます。これは、必要なスタイルシートとスクリプトへの参照をすべて含んだ、より洗練された jQuery Mobile Web ページを構築するための簡単なスタート地点です。

jQuery Mobile ボイラープレートページを返却するように、シンプルな Delphi WebBroker アプリケーションを変更してみましょう。

最初に、“TWebModuleMain.WebModuleMainDefaultHandlerAction” イベントハンドラを削除します。最も簡単な方法は、そのイベントの本体部分を削除して “保存” をクリックすることです。これで、イベントハンドラを完全に削除します。

Web モジュールのコードエディタとフォームデザイナ間の切り替えを行うために F12 キーを押します。Web モジュール上に、“TPageProducer” コンポーネントをドロップします。

“DefaultHandler” Web アクションアイテムを選択し、その “Producer” プロパティを設定して、Web モジュールに追加されたばかりの “PageProducer1” コンポーネントを指すようにします。

“PageProducer1” コンポーネントを選択し、オブジェクトインスペクタ内の “HTMLDoc” プロパティを開きます。

以下の jQuery Mobile ボイラープレートテンプレートをコピー&ペーストします。

<!DOCTYPE html> 
<html> 
<head> 
<title>Page Title</title> 
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>
</head> 
<body> 

<div data-role="page">

     <div data-role="header">
          <h1>Page Title</h1>
     </div><!-- /header -->

     <div data-role="content">    
          <p>Page content goes here.</p>          
     </div><!-- /content -->

     <div data-role="footer">
          <h4>Page Footer</h4>
     </div><!-- /footer -->
</div><!-- /page -->

</body>
</html>

アプリケーションを実行すると、ブラウザが開き、以下のページが表示されるはずです。

これは古いブラウザでは動きません。私は Chrome を使用しています。

Hide image
Boilerplate

HTML コードが完全にアプリケーション内にハードコードされています。 “HTMLDoc” プロパティを使う代わりに “HTMLFile” を使用することができます。最終的なアプリケーションのコンテンツが動的に生成されるので、ここで “HTMLDoc” を使用することを好みます。しかしそれほど問題にはなりません。

jQueryMobile は、ひとつの html ドキュメント内に複数の “page” を定義することができます。これを使用するつもりです。jQueryMobile は、それぞれの html タグを装飾するために “data-*” 属性を使用します。複数のモバイル “page” をホストするために、“data-role=page” 属性を持つ複数の “div” を使用する必要があります。最初にメインページを検討します。

“TPageProducer” コンポーネントは、動的な HTML コンテンツを提供するために使うことが可能な “OnHTMLTag” イベントを提供します。

“#” シンボルでマークされた特別なタグごとに PageProducer コンポーネントによって “OnHTMLTag” イベントが呼び出され、それにより、プログラムで正しい値を提供することが可能になります。

その動作を理解するために参考になるのは、“ReverseString.html” ファイルを調べることです。そして、それに対応する PageProducer は、“DataSnap REST アプリケーション” ウィザードによって生成されたプロジェクトです。

2つのカスタムタグを使用します。一つは html ドキュメントタイトル (“#doctitle”) 用、そして、もう一つは、jQueryMobile ボイラープレートテンプレートの body 全体 (“#docbody”) 用です。

“PageProducer1” コンポーネントを再び選択し、オブジェクトインスペクタ内で “HTMLDoc” プロパティを開きます。

エディタ内で、「すべて選択」し、透過的なタグを含んだ以下のコードに置き換えます。

<!DOCTYPE html> 
<html> 
<head> 
<title><#doctitle></title> 
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0a3/jquery.mobile-1.0a3.min.js"></script>
</head> 
<body> 
<#docbody>
</body>
</html>

“TPageProducer” コンポーネントを選択します。オブジェクトインスペクタ内で、このイベント用の空のイベントハンドラを生成するための “OnHTMLTag” をダブルクリックし、jQueryMobile ボイラープレートを動的に生成する以下のコードを入力します。

procedure TWebModuleMain.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
  const TagString: string; TagParams: TStrings; var ReplaceText: string);
begin
  if SameText(TagString, 'doctitle') then
    ReplaceText := 'Page Title’

  else if SameText(TagString, 'docbody') then
    ReplaceText :=

 '<div data-role="page">'

+'  <div data-role="header">'
+'       <h1>Page Title</h1>'
+'  </div><!-- /header -->'

+'  <div data-role="content">'
+'       <p>Page content goes here.</p>'
+'  </div><!-- /content -->'

+'  <div data-role="footer">'
+'       <h4>Page Footer</h4>'
+'  </div><!-- /footer -->'

+'</div><!-- /page -->'

  else
    ReplaceText := '';
end;

Web アプリケーションを再実行すると、依然として同じ jQueryMobile ボイラープレートページを表示することを確認できるはずです。

    動的ページ作成のリファクタリング

現在、すべてのマークアップは、WebBroker の透過的なタグである “#DocTitle” と “#DocBody” 用に置換マークアップを提供する “OnHTMLTag” イベント内で動的に生成されています。

今回の Web ドキュメントの実際の body を生成すめためのコードがとても複雑になりかねないので、この機能を別のデータモジュールとして抽出するのはどうでしょうか? オン・ザ・フライで、このデータモジュールを生成と破棄することができ、HTML ドキュメントの動的 body を Delphi 文字列として返却するパブリックメソッドとドキュメントタイトルを返却するためのパブリックメソッドを持つことが必要です。

IDE のメニューより [ファイル|新規作成|その他] を選択し、「新規作成」ダイアログ内の 「Delphi プロジェクト|Delphi ファイル」カテゴリを選び、「データモジュール」アイコン上でダブルクリックします。

Hide image
DataSnap96

新しいユニットを “DataModuleHtmlUnit” として保存し、オブジェクトインスペクタ内のデータモジュール名を “DataModuleHtml” に変更します。

動的ページの動的な html コンテンツの生成のプロセスの間、実行形式でこのデータモジュールクラスの生成と破棄を行います。

IDE のメニューから [プロジェクト|オプション] を選択し、このデータモジュールのインスタンス化は、今回のアプリケーションには必要ないので、プロジェクトに追加されたばかりのデータモジュールを自動生成フォームの一覧から削除します。私は、定義ユニットのグローバルな変数をコメントアウトするのが好みです。こうすれば、間違って使用されるは決してありません。

Hide image
Click to see full-sized image

expand view>>

“OnHTMLTag” イベントハンドラで使用する文字列を返却する “GetBody” と呼ばれるデータモジュールクラスのパブリックメソッドを実装しましょう。

ここでは、Web モジュールの実装は以下のようになり、“OnHTMLTag” イベントハンドラの実装を変更しています。

unit WebModuleUnit;

interface

uses
  SysUtils, Classes, HTTPApp, HTTPProd;

type
  TWebModuleMain = class(TWebModule)
    PageProducer1: TPageProducer;
    procedure PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
      const TagString: string; TagParams: TStrings; var ReplaceText: string);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  WebModuleClass: TComponentClass = TWebModuleMain;

implementation

uses DataModuleHtmlUnit;

{$R *.dfm}

procedure TWebModuleMain.PageProducer1HTMLTag(Sender: TObject; Tag: TTag;
  const TagString: string; TagParams: TStrings; var ReplaceText: string);

var 
 dm: TDataModuleHtml;

begin
  dm := TDataModuleHtml.Create(nil);
  try

    if SameText(TagString, 'doctitle') then
      ReplaceText := dm.GetTitle

    else if SameText(TagString, 'docbody') then
      ReplaceText := dm.GetBody

    else
      ReplaceText := '';

  finally
    dm.Free;
  end;
end;

end.

そして、これがクライアントプロジェクトへ追加された新しいデータモジュールクラスの実装です。

unit DataModuleHtmlUnit;

interface

uses
  SysUtils, Classes;

type
  TDataModuleHtml = class(TDataModule)
  private
    { Private declarations }
  public
    function GetTitle: string;
    function GetBody: string;
  end;

//var
//  DataModuleHtml: TDataModuleHtml;

implementation

{$R *.dfm}

{ TDataModuleHtml }

function TDataModuleHtml.GetTitle: string;
begin
  Result := 'WebBroker jQueryMobile Boilerplate';
end;

function TDataModuleHtml.GetBody: string;
begin
  Result :=

 '<div data-role="page">'

+'  <div data-role="header">'
+'       <h1>Page Title</h1>'
+'  </div><!-- /header -->'

+'  <div data-role="content">'
+'       <p>Page content goes here.</p>'
+'  </div><!-- /content -->'

+'  <div data-role="footer">'
+'       <h4>Page Footer</h4>'
+'  </div><!-- /footer -->'

+'</div><!-- /page -->'

end;

end.

Web アプリケーションを起動すると、依然として前と同じ jQueryMobile ボイラープレートページを表示することを確認できるはずです。

リファクタリングの全体的な考えは、その動作を変えることなく、コードの基本構造を変えることです。DataSnap サーバーからのデータに基づいて “GetBody” の実装を行い、実際の複雑な動作を処理する準備が整いました。

    まとめ

この DelphiLabs の DataSnap チュートリアルでは、モバイルデバイス上でデータベースのデータを表示を行う多層でスケーラブルなシステムを構築する実践的な手順をご覧頂きました。

最初のパートでは、Web アプリケーション構築のための Delphi WebBroker フレームワークについて検討し、WebBroker jQueryMobile ボイラープレートページを構築するためにも同じく Delphi を使用しました。

動的 HTML マークアップ生成のコードのリファクタリングを行った後、チュートリアルの2番目のパートの準備が行いました。そこでは、サンプルの InterBase データベースから顧客データを返却する DataSnap サーバーを構築し、それを jQueryMobile Web フロントエンドを動的に構築するために使用します。

このチュートリアルでは、jQueryMobile ライブラリのプレリリースバージョンを使用しており、最終的な機能は、ここで記載されているものと異なる可能性があることに注意してください。

DataSnap は Delphi, C++Builder, RAD Studio の Enterprise および Architect エディションの機能です。Starter および Professional エディションには搭載されておりません。

    参考資料

Server Response from: ETNASC03