目次


マッシュアップ、レポートを超える機能

IBM Mashup Center リレーショナル更新フィードと組み合わせて使用するフォーム・ウィジェットの構築

Comments

概要

ほとんどの開発者は、データベース・テーブルに簡単な更新を行うアプリケーションの構築が必要となる場合があります。IBM Mashup Center バージョン 2 から、INSERT、UPDATE、または DELETE といった単一のSQL ステートメントの実行が可能なリレーショナル (JDBC) フィードを容易に作成できるようになりました。この記事では、そのようなフィードをマッシュアップ・アプリケーションで活用するために役立つウィジェットの開発方法について説明します。

この記事は、読者がすでにマッシュアップとフィードの構築やウィジェット作成の基本に習熟されていることを前提としています。特に、JavaScript でのプログラミング方法の知識と、IBM Mashup Center の使用経験が必要です。「リソース」セクションには、「Creating a feed from an enterprise database (JDBC)」と「Developing widgets for IBM Mashup Center」という 2 つのリンクがあります。どちらの項目にも、マッシュアップ構築の基本を素早く理解するために役立つ入門的な情報が含まれています。

リレーショナル更新フィード

IBM Mashup Center を使用すると、リレーショナル照会から返されたデータに基づいてフィードを作成できます。関心のあるテーブルおよび列を選択するか、データベースに照会を実行する SQL ステートメントを使うことにより、フィードが作成されます。フィードは、照会の結果セットとして返されたデータから作成します。

IBM Mashup Center の V2 から、SELECT SQL ステートメントの使用に加え、リレーショナル・フィード・ジェネレーターを使用して、INSERT、UPDATE、または DELETE の各 SQL ステートメントも実行できます。単一の SQL ステートメントだけを実行できるため、この機能は複雑なトランザクション処理での使用には向きません。しかし、この更新機能を使用して、下例に示すように、比較的簡単な多数のシナリオをサポートできます。

  • スナップショットを得てトレンド分析を行う。たとえば、毎日の新規注文の合計数を返すフィードを持っているものとします。実行したフィード・コンテンツをデータベース・テーブルに保存することで、注文の出荷傾向を示すフィードを生成できます。データ・マッシュアップ・エディターを使用すると、FOREACH 演算子を用いて、繰り返しの各エントリーからコンテンツをそれぞれの行に挿入 (INSERT) するデータ・マッシュアップを作成できます。
  • コメントまたはメモを保持する。たとえば、ユーザーの好みや意見を収集する簡単なアンケート・アプリケーションを作成できます。
  • データベースに保持されているタスク・リストを維持するフォームを開発する。
  • サービス要求を送信するフォームを開発する。たとえば、建物、プリンター、または IT システムなどのサービス要求が可能です。

リレーショナル更新フィードを単純に使用するマッシュアップ・ページの構築がわかりにくいことがあります。たとえば、IBM Mashup Center に用意されているユーザー入力ウィジェットを使用して、ユーザーからの入力を収集するテキスト・ボックスなどのコントロールを生成できます。しかし、ユーザー入力ウィジェットはリレーショナル更新フィードを直接実行することができず、実行結果を優れた方法で表示するウィジェットもありません。

この記事では、上記の 2 番目に示したタイプのシナリオについて、リレーショナル更新フィードを使いやすくするカスタム・ウィジェットの構築方法を説明します。カスタム・ウィジェットは、HTML フォームを構成パラメーターとして受け取ります。そして、フォームをレンダリングし、フォーム・データをリレーショナル更新フィードに送信して、更新状況を表示します。このカスタム・ウィジェットは任意の HTML フォーム・フラグメントを受け入れるため、フォームのレイアウトをより強力に制御できます。また、HTML フォーム・フラグメントの使用によって、複数のページで同じフォームを作成しやすくなります。次のセクションでは、サンプル・シナリオから説明を開始し、HTML フォーム・ウィジェットの機能を紹介します。

サンプル・シナリオ

セットアップを最小限にし、手順を進めやすくするために、サンプル・シナリオでは IBM Mashup Center とともにインストールされる Apache Derby サンプル・データベースに含まれるポリシー・テーブルを使用します。図 1 に、この記事で構築方法を説明するサンプルのマッシュアップ・アプリケーションのスクリーン・ショットを示します。このアプリケーションは大変シンプルで、2 つのウィジェットで構成されています。

図 1. サンプルのマッシュアップ・ページ
サンプルのマッシュアップ・ページ
サンプルのマッシュアップ・ページ

図 1 からわかるように、DataViewer ウィジェットが左側で使用され、データベースから取得した、関心のあるポリシーのリストが表示されています。行 (ポリシー) を選択すると、そのポリシーに関する詳細情報が右側の HTML フォーム・ウィジェットに表示されます。ユーザーは HTML フォーム・ウィジェットでアドレスを変更し、送信ボタンを押すことができます。ボタンはリレーショナル更新フィードを実行するように構成されています。実行の結果は XML 文書になっています。XML 文書が解析され、成功または失敗を示すシンプルなメッセージが表示されます。成功のメッセージを図 2 に示します。

すぐにサンプル・ウィジェットに手を加え、独自のフォームで使用したい場合は、「ダウンロード」セクションからサンプル・ウィジェットを入手し、IBM Mashup Center に追加できます。そして、ウィジェットの構築方法の説明をスキップし、「すべてを組み合わせる」のセクションに進んでください。

図 2. 実行が成功したときに表示されるメッセージ
実行が成功したときに表示されるメッセージ
実行が成功したときに表示されるメッセージ

上記の機能をサポートするウィジェットの構築を始める前に、もう 1 つ注意が必要な点として、リレーショナル・フィードの定義があります。次のセクションでは、その方法を説明します。

JDBC フィードの作成

前述のように、手順を進めやすくするために、この記事で説明するサンプル・シナリオでは、IBM Mashup Center サンプル・データベースに含まれているポリシー・テーブルを使用します。

次の手順に従い、ポリシー・テーブル用のリレーショナル・フィードを作成します。

  1. カタログのホーム・ページに移動し、「作成」をクリックします。
  2. 新規フィード」を選択します。
  3. フィード・データ・ソースとして、「エンタープライズ・データベース (JDBC) 」を選択します。
  4. ポリシー・テーブルが含まれるデータベースにアクセスするために、「接続プロファイル」フィールドで「Mashup Hub Sample Database」を選択します。

    プロファイルがまだ存在しない場合は、次の情報を指定して作成します。

    • 接続プロファイル名: MashupHub Sample Database
    • データベース・タイプ:組み込み Derby
    • 接続タイプ:ドライバー・マネージャー (非管理対象接続)
    • データベース名: <installDir>/Hub/installedApps/Mashup Hub.ear/mashuphub-enterprise.war/hubsample
  5. 次の SQL ステートメントを使用して、図 1 に示した 2 つのウィジェットに対応する 2 つのフィードを作成します。
    • 最初のフィードは、ポリシーのリストを表示する DataViewer ウィジェット用です。state パラメーターを追加することで、特定の状況によってポリシーをフィルターできます。
      select * from samples.policyholders where state = ':state'
    • 2 番目のフィードは、HTML フォーム・ウィジェットによって使用されるリレーショナル更新フィード用です。
      update samples.policyholders set address = ':address', city = ':city', 
      state = ':state' where policyid = ':policyid'

    この記事では、読者がすでに IBM Mashup Center を使用してリレーショナル・フィードを作成することに慣れているものとして説明を進めます。どちらの照会もパラメーターを使用するため、SQL ステートメントを JDBC フィード・エディターの「詳細」ボックスに貼り付けることによって、フィードを作成する必要があります。リレーショナル・フィードの作成の詳細については、「リソース」セクションに含まれるリンクを参照してください。

先に進む前に、ここではよい機会として、リレーショナル更新フィードを使用する上で特に注意が必要となる点を確認しておきましょう。

  • HTTP GET を使用する

    リソース」セクションにリストされた W3C の記事で説明されているように、「対話によってリソースの状況が、ユーザーに知覚される形で変更される (たとえば、サービスの購読)」場合は、HTTP POST を使用する必要があります。その 1 つの理由は、HTTP GET の URL は容易にブックマークおよびキャッシュすることができ、偶発的で予期せぬ呼び出しが発生する可能性があるからです。この記事で開発する HTML フォーム・ウィジェットは、アクセス方式として HTTP POST を使用します。IBM Mashup Center では、デフォルトで GET と POST の両方がサポートされます。HTTP GET アクセスを無効にするには、フィード詳細ページで「アクセス方式」ボタンを展開し、「GET」チェック・ボックスを選択解除します。

  • 行の重複を避ける

    リレーショナル更新フィードは単一の SQL ステートメントで構成されています。エラー処理ロジックがないため、データの意味的な整合性を保つためにデータベースの制約に頼らなければなりません。たとえば、行の重複を避けるには、1 つの列を KEY 列として宣言し、前のキーを使用した行の挿入が失敗するようにしなければなりません。

  • キャッシュ

    ほとんどの場合、更新を行うフィードはキャッシュすべきではありません。ただし、更新フィードがデータ・マッシュアップで使用される場合は例外です。編集中にキャッシュしないと、出力がプレビューされるたびに、更新フィードが実行されます。デフォルトでは、source 演算子によって、その入力フィードが 1 時間キャッシュされます。これはまさに、マッシュアップの作成中に必要なことです。完了したマッシュアップを保存する直前に、リレーショナル更新フィードを使用するすべての source 演算子でキャッシュをオフにする必要があります。

これらの考慮事項を踏まえ、カスタム HTML フォーム・ウィジェットを構築する準備が整いました。

ウィジェットの開発

Mashup Center のウィジェットは iWidget 仕様に準拠します。ウィジェットには次の 2 つのタイプがあります。2 つのウィジェット間の主な違いは、デプロイメントの方式です。

  • WAR ファイルに基づくウィジェット — サーバー・ベースのコンポーネントを保持することができ、アプリケーション・サーバー上にデプロイする必要があります。
  • 軽量ウィジェット — クライアント・サイドで完全に動作し、アプリケーション・サーバー上にデプロイする必要はありません。この記事で説明するサンプルの HTML フォーム・ウィジェットは軽量ウィジェットです。

以下の手順に従い、IBM Mashup Center バージョン 2 を使用して、サンプルの HTML フォーム・ウィジェットの開発を始めます。

  1. 図 3 に示すように、マッシュアップ・ビルダー・ページの右上隅にある「表示へジャンプ」をクリックし、「新規ウィジェットの作成」を選択します。
    図 3. 「新規ウィジェットの作成」メニュー
    「新規ウィジェットの作成」メニュー
  2. 図 4 に示すように、「ウィジェット・ビルダー」ダイアログで「ウィジェット・エディターの操作」を選択します。
    図 4. 「ウィジェット・ビルダー」ダイアログ
    「ウィジェット・ビルダー」ダイアログ
    「ウィジェット・ビルダー」ダイアログ
  3. 次のダイアログで「新規プロジェクトの作成」を選択します。
  4. 「新規ウィジェット・プロジェクト」ダイアログで「 プロジェクトをスターター・ファイルから作成します」を選択します。スケルトンのウィジェット定義とカタログ・ファイルを持つ新規プロジェクトが作成されます。すべてのファイルはサーバーによって維持されます。図 5 に示すように、「カスタマイズ・ウィジェット・プロジェクト」ダイアログの「ファイルの選択」見出しの下にファイルの名前が表示されます。リストの下のボタンを使用すると、任意の既存ファイルを選択して編集したり、追加ファイルをプロジェクトにアップロードしたりすることができます。
    図 5. 「カスタマイズ・ウィジェット・プロジェクト」ダイアログ
    「カスタマイズ・ウィジェット・プロジェクト」ダイアログ
    「カスタマイズ・ウィジェット・プロジェクト」ダイアログ
  5. テストの準備ができたら、「エクスポート」をクリックし、「パレットに追加」を選択します。

この記事のサンプル・プロジェクトは大変シンプルで、ファイルは 2 つしかありません。

ウィジェット定義ファイル

生成された catalog.xml ファイルを変更する必要はありません。これは、ツールボックス・メニューに表示されるウィジェット名とウィジェット定義ファイル (iWidget.xml) の場所を提供するだけのファイルです。iWidget.xml ファイルでは、ロジックをインプリメントする JavaScript ファイル、ウィジェットによって送受信される静的イベント、表示モードでのレイアウト、および編集モードでのレイアウトを指定します。このセクションでは、iWidget.xml に必要な変更を順番に見ていき、それぞれの領域について説明します。

iWidget.xml ファイルのルート要素をリスト 1 に示します。最も重要なのは、iwidget ルート要素内の iScope 属性です。この属性は、iWidget コールバック関数をインプリメントする JavaScript オブジェクトを指定します。JavaScript を含むファイルは、リソース要素を使用してロードされます。属性の詳細については、「リソース」セクションに記載されているウィジェット・プログラミングおよび API ドキュメンテーションのリンクを参照してください。

リスト 1. iWidget.xml ヘッダー
<iw:iwidget name="htmlForm"
            xmlns:iw="http://www.ibm.com/xmlns/prod/iWidget"
            iScope="sample.mashupcenter.htmlForm"
	    allowInstanceContent="true" supportedModes="view edit"
            mode="view" lang="en">

<iw:resource uri="htmlForm.js"/>

リスト 2 は、ウィジェットの定義済みの受信イベント (1 つ) と送信イベント (2 つ) の定義を示しています。受信イベントであることは、handled 属性と onEvent 属性があることでわかります。onEvent 属性の値は、イベントを受信したときに呼び出す関数の名前です。published 属性の値は、パブリッシュされたイベントの名前を定義します。この記事の後半の「イベントの処理と生成」セクションで、これらのイベントの処理方法を説明します。

リスト 2. iWidget.xml のイベント仕様
<iw:event id="ResetForm" handled="true" onEvent="handleReset"
          eventDescName="desc_handleReset"/>
<iw:eventDescription id="desc_handleReset" payloadType="any" title="Clear all Fields"
                        description="Clear all the fields in the form" lang="en">
</iw:eventDescription>

<iw:event id="actionSuccessful" eventDescName="desc_actionSuccessful" published="true"/>
<iw:eventDescription id="desc_actionSuccessful" payloadType="text"
                        description="Number of records updated by WebService" lang="en">
</iw:eventDescription>

<iw:event id="actionFailed" eventDescName="desc_actionFailed" published="true" />
<iw:eventDescription id="desc_actionFailed" payloadType="text"
                        description="Failure to assign" lang="en">
</iw:eventDescription>

最後に、ウィジェット定義ファイルでは、表示モードと編集モードのウィジェット・レイアウトも指定します。レイアウトは、iw:content 要素の CDATA として含まれる HTML マークアップによって指定します。リスト 3 に、表示モード用の HTML マークアップを示します。JavaScript による操作を可能にするために、すべての div 要素が id を持っていることに注意してください。また、各 id の値は _IWID_ を接頭辞として使用します。ランタイムのウィジェット作成時に、IBM Mashup Center によって、すべての _IWID_ 接頭辞が実際の固有のウィジェット・インスタンス ID に置換されます。これにより、同じ HTML ページにウィジェットの複数のインスタンスが存在する場合でも、すべての id が固有になります。表示モードの定義には、2 つの div 要素があります。_IWID_formdiv という id の div には HTML フォーム・フラグメントが含まれ、初期状態ではブランクです。もう一方の div には display:none のstyle 仕様が含まれ、この要素が非表示あることを意味します。この要素には、フォーム送信の結果を表示するためのテンプレートが含まれていて、更新フィードのいずれかを実行した後に、JavaScript によって表示できます。

リスト 3. iWidget.xml の表示モードのレイアウト
<iw:content mode="view">
  <![CDATA[
  <div id='_IWID_formdiv'></div>

  <div id='_IWID_resultdiv' style='display:none; font-size:1.3em;'>
      <div id="_IWID_ResultXML" ></div>
      <br />
      <a href=""
         onclick="javascript:iContext.iScope().showFormAndHideResult();return false;">
         Back</a>
  </div>

  ]]>
</iw:content>

編集モード・セクションには、1 つのテキスト・エリアと 3 つのテキスト・ボックスを持つフォームのコードがあります。このフォームは、ユーザーが「設定の編集をクリックしたときに表示されます。テキスト・エリアは、HTML フォーム・フラグメントを入力するために使用されます。3 つのテキスト・ボックスには、合計 3 つまでの URL を入力できます。これらの URL をフォーム上のボタンと関連付ける方法については、後のセクションで説明します。URL の値は、フォームの method 属性に入力される値と同じでなければなりません。つまり、? 文字に続く名前の値のペアが取り除かれた URL です。

htmlForm 編集 ダイアログ」には、レンダリングされたフォームのスクリーン・ショットが表示されます。簡潔にするために、この記事では編集モードの HTML レイアウトの全体は再現しません。このレイアウトは、「リソース」セクションの適切なリンクからダウンロードできる完全なウィジェット・パッケージの一部として利用できます。

JavaScript のインプリメンテーション

JavaScript インプリメンテーション・ファイルの名前は htmlForm.js です。これは、load、unload、view、edit などの標準イベントと、他のカスタム・イベントおよびサーバー通信を処理する Dojo クラスです。このファイルに含まれる関数の概要を以下で簡単に示します。

  • onLoad — この関数は、初期化コードを配置した場所にあります。通常、この関数には、「設定の編集」ダイアログの前の呼び出しで保存された構成情報の取得が含まれています。

    表示モードおよび編集モードの HTML マークアップに含まれるすべての id 属性は _IWID_ 接頭辞を持っていて、この接頭辞は、ウィジェットの作成時に実際のウィジェット・インスタンス id に置換されることを思い出してください。これは、JavaScript コードが id によって識別された HTML 要素を取得する前に、iContext オブジェクトからのインスタンス・ウィジェット id を使用して、実際の id を作成する必要があることを意味します。リスト 4 に、iContext に関連するウィジェットの attributes オブジェクトからウィジェット構成データを取得する方法を示します。

    リスト 4. onLoad 関数
    onLoad: function() {
    
            this.uid = "_" + this.iContext.widgetId + "_";
    
            this.formDivNode   = dojo.byId(this.uid + 'formdiv');
            this.resultNode = dojo.byId(this.uid + 'resultdiv');
    
            // load attributes
            var attributes = this.iContext.getiWidgetAttributes();
            this.formHtml  = attributes.getItemValue( "formHtml" );
            ::::::::::::::::::::::::
    },
  • onUnload — この関数は、ページが切り替えられる直前に呼び出されます。通常、クリーンアップは不要です。つまり、この関数をインプリメントする必要はありません。しかし、Dojo V1.3 Dijit ID は固有でなければならず、ページ間の切り替え時のクリーンアップでは自動的に削除されないため、手動で削除する必要があります。
    リスト 5. onUnload 関数
    onUnload: function()
    {
        // need to clear all existing dijits (to free up id's)
        if ( this.formDijit != null )
            this.formDijit.destroyRecursive( false );
    },
  • onview — この関数は、ウィジェットが表示されるときに必ず呼び出されます。サンプル・ウィジェットでは、ウィジェットが構成されていない場合 (たとえば、初めてページ上にドラッグされた場合) は、単にデフォルト・メッセージが表示されます。それ以外の関数については、以降のセクションで詳しく説明します。
    リスト 6. onview 関数
    onview: function()
    {
        if ( this.formHtml == null  ||  this.formHtml.length <= 0 ) {
            this.formDivNode.innerHTML = "Switch To Edit to specify HTML form";
        } else if ( this.viewContent.length <= 0 ) {
            this.displayForm();
            this.reCreateEvents( );
        }  // else form already there, no need to do anything
    },
  • onedit — この関数は、「設定の編集」がクリックされたときに呼び出されます。リスト 7 のコードでは、前の呼び出しでユーザーから提供された値を使用して、「設定の編集」ダイアログを事前に生成しています。
    リスト 7. onedit 関数
    onedit: function()
    {
        dojo.byId( this.uid + "formHtml" ).value = this.formHtml;
        :::::::::::::::::::::::::::::::::::
    },
  • saveConfigData — この関数は、どの組み込みイベントとも対応していません。これは、編集モードの HTML マークアップにある「保存」ボタンの onclick メソッドで指定されるウィジェット固有の関数です。リスト 8 のコードでは、最後のユーザーによって提供された値を「設定の編集」ダイアログから取得し、保存しています。onModeChanged イベントを使用して、「設定の編集」ダイアログの廃棄をウィジェット・ランタイムに通知します。
    リスト 8. saveConfigData 関数
    saveConfigData: function()
    {
        this.formHtml = dojo.byId( this.uid + "formHtml" ).value;
        ::::::::::::::::::::::::::::::::::::::::::::::::::
    
        this.iContext.iEvents.fireEvent("onModeChanged", null, "{newMode:'view'}");
    
        var attributes = this.iContext.getiWidgetAttributes();
        attributes.setItemValue("formHtml"  ,  this.formHtml );
        ::::::::::::::::::::::::::::::::::::::::::::::::::
        attributes.save();
    },

リソース」セクションには、ウィジェット・パッケージ全体をダウンロードできるリンクがあります。これまでに、すべてのウィジェットに共通する関数への理解を深めたので、次のセクションでは、サンプル・ウィジェット固有の関数について見ていきましょう。

HTML フォームの表示

ウィジェットを使用するには、HTML フォームが必要です。フォームは、任意のエディターや好みのコード生成ツールを使用して作成できます。HTML フォームを作成した後は、フォームの各入力フィールドに適切な dojotype 属性があることを確認します (たとえば、「すべてを組み合わせる」セクション内のサンプル HTML リストを参照)。フォームには複数のボタンを配置できます。アクティブにするボタンには、次のような値を持つ onclick 属性が必要です。

            onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"

上記は、ウィジェットの JavaScript ファイルで定義された submit 関数を呼び出す構文です。「フォーム送信の処理」セクションで、submit 関数を処理する方法の詳細が説明されています。ここでは、上例の ${widgetId} サブストリングをウィジェットの実際の ID で単に置換し、有効な JavaScript にしています。この実行方法を次に説明します。

「設定の編集」ダイアログに貼り付けられた HTML フォーム・フラグメントを表示するには、HTML ストリングを innerHTML に代入します。この innerHTML は、iWidget.xml 表示モード・レイアウトのプレースホルダー用の div に含まれています (リスト 9 参照)。ただし、代入する前に、${widgetId} ストリングを実際のウィジェット ID で置換する必要があります。この置換を行うには、Dojo ストリング・ユーティリティー関数のsubstitute を呼び出します。これもリスト 9 に示されています。リスト 9 のコードに関する最後の注意点として、フォームには Dojo Dijits が含まれるため、Dojo の parse メソッドを呼び出して、Dojo の動作を有効にしなければなりません。

リスト 9. displayForm 関数
displayForm: function()
{
    // fix up button onclick action to point to submit method of this widget.
    this.viewContent = dojo.string.substitute( this.formHtml
                                             , { widgetId: this.iContext.widgetId });
"
    // Add form content to the view content root node.
    if ( this.formDijit != null )  // need to clear all existing dijits (to free up id's)
        this.formDijit.destroyRecursive( false );
    this.formDivNode.innerHTML = this.viewContent;

    // Parse dojo components to display Dojo widgets
    dojo.parser.parse( this.formDivNode );
    this.formDijit = this.getFormDijit(  this.formDivNode );
},

イベントの処理と生成

サンプル HTML フォーム・ウィジェットの重要な機能の 1 つとして、データをウィジェットにワイヤリングできることが挙げられます。「サンプル・シナリオ」セクションで述べたように、DataViewer ウィジェットの行をクリックすると、その行の列がウィジェット内のフォームの入力フィールドに渡されます。フォームの入力フィールドはフォームによって異なる可能性があります。このため、iWidget.xml イベント仕様 では受信イベントと 2 つの送信イベントを事前に定義しましたが、iWidget.xml ファイルではフォームの入力フィールドの受信イベントを静的に定義することはできません。

フォームの入力フィールドごとにイベントを動的に作成するには、フォームのすべての入力フィールドの HTML を最初に解析する必要があります (リスト 10 参照)。

リスト 10. createEventsForFields 関数
createEventsForFields : function(  )
{   
    this.eventNames = [];
    this.dijitMap   = {};

    var children = this.formDijit.getChildren();
    for (var i = 0  ;  i < children.length  ;  i++ ) {
        var widget = children[i];
        var name  = widget.attr( 'name' );
        if ( name == null ||  name.length == 0 )
            continue;  // skip over unnamed form input fields
        if ( widget.type == 'radio'  &&  widget.checked == false )
            continue;   // for radio button, pick the one that is true

フォームの入力フィールドを識別した後、そのフィールドのイベントを同じ名前で作成します (図 11 参照)。

リスト 11. イベントの動的作成
this.eventNames.push( name );
this._createEvent({
    name : name,
    type: "any",
    isHandled : true,
    handlingFn : dojo.hitch(this, this.handleEvent )
});

for ループの最後で、各イベントを dijitMap に追加します (リスト 12 参照)。このマップは、後でイベントが呼び出されたときに、正しいイベントを起動するために使用されます。

リスト 12. dijitMap へのイベント名の格納
// will also create dijit mapping to process event
this.dijitMap[ name ] = widget;

次に、これらのイベントの起動時にイベントを処理するコードを配置しなければなりません。上記に示したイベントの 1 つがウィジェットにワイヤリングされているときは、イベント名を使用してフォームの正しい入力フィールドが (dijitMap コードの補助により) 見つけられます。フォームの入力フィールドが null でない場合は、ウィジェットの値として受け取るペイロードを設定します (リスト 14 参照)。

リスト 14. handleEvent 関数
handleEvent: function(iEvent){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var  evtname    = iEvent.name;
    var  widget     = this.dijitMap[ evtname ];
    if ( widget != null )
        widget.setValue( iEvent.payload ); 
}

フォーム送信の処理

HTML フォームの表示」セクションで述べたように、HTML フォーム・フラグメント内のボタンには、submit 関数への明示的な呼び出しを含める必要があります。submit 関数への引数によって、ボタンが押されたときに、「htmlForm 編集」ダイアログ で定義されたどのフィード URL を実行するのかが定義されます。リスト 15 に示すように、引数は次のいずれかのストリングでなければなりません。

  • formUrl1 — フォームの最初のメソッドで定義されたフィード URL を実行します。
  • formUrl2 — フォームの 2 番目のメソッドで定義されたフィード URL を実行します。
  • formUrl3 — フォームの 3 番目のメソッドで定義されたフィード URL を実行します。
リスト 15. submit 関数
submit: function( action ) {
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    var actionURL = "";
    //Specify the root URL of the feed that you want to trigger:
    if ( action == 'formUrl1' ) {
        if (  this.formUrl1  &&  this.formUrl1.length > 0 )
            actionURL = this.formUrl1;
    } else if ( action == 'formUrl2' ) {
        if (  this.formUrl2  &&  this.formUrl2.length > 0 )
            actionURL = this.formUrl2;
    } else if ( action == 'formUrl3' ) {
        if (  this.formUrl3  &&  this.formUrl3.length > 0 )
            actionURL = this.formUrl3; 
    ::::::::::::::::::::::::::::::::::::::::::::::::::

これで、選択されたアクションに対応する正しいベース URL を得られたので、ユーザーが入力したフォームの値を収集する必要があります。これには、collectNVP 関数を使用します。リスト 16 に示すように、フォーム内の異なる種類の入力フィールドから値を取得する退屈な作業は、Dojo ライブラリーのフォーム用の Dijit getValues 関数によってすべて処理されます。コードでは、ループによって各フィールドにアクセスし、値をエンコードして無効な文字が含まれないようにします。

リスト 16. collectNVP 関数
collectNVP: function(  ) {
    this.debugTrace( "collectNVP entered" );

    var formData = "";
    var temp = this.formDijit.getValues();
    for ( var  name in temp ) {
        if ( formData.length > 1 )  formData += '&';
        //Encode the key and value, to make sure there are no invalid characters.
        formData +=  encodeURI( name );
        formData +=  "=";
        // encodeURI( value );   doesn't escape &, ...
        var value =  temp[ name ];
        formData +=  escape( value );
    }
    return formData;
}

フォーム・データおよびベース URL を収集した後は、Dojo ライブラリーの xhrPost メソッドを使用して AJAX 呼び出しを送信します。「JDBC フィードの作成」セクションでのアドバイスに従い、HTTP GET でなく、HTTP Post をアクセス方式として使用し、リレーショナル更新フィードを実行します。

リスト 17 に示すように、xhrPost メソッドへの引数には、load (成功) および error の場合のコールバック関数が含まれています。これらのコールバック関数の詳細については、次の 2 つのセクションで説明します。ベース URL またはフォーム・メソッドを含む urlToLoad 引数は、直接使用されません。その理由は、ブラウザーのサンドボックス・ルールにより、ユーザーが入力したベース URL は、リダイレクトしてマッシュアップ・サーバー AJAX プロキシーを通過させる必要があるからです。これは、iContext を通じてアクセス可能な reWriteURI 関数を呼び出すことによって行います。

リスト 17. フォームの送信
// Using POST for update type URL
submitUrl: function(urlToLoad, formdata )
    var location = this.iContext.io.rewriteURI( urlToLoad );
    dojo.xhrPost({
        url     : location,
        postData: formdata,
        load    :  dojo.hitch( this, this.handleFeedContent ),
        error   :  dojo.hitch( this, this.handleErrorResponse ),
        handleAs: "xml",
        sync    : true
    });
}

フォーム・データの送信が成功したときの処理

xhrPost AJAX 呼び出しで指定したように、フォームの送信が成功すると、handleFeedConent 関数が呼び出されます。このウィジェットは、MashupCenter のリレーショナル (JDBC) 更新フィードでのみ機能するように設計されています。図 6 に示すように、フィードは XML 応答を返します。異なる応答が取得されたときは、「サポートされていない結果フォーマット」が返されたことを示すメッセージがプログラムによって表示されます。

図 6. 成功時の更新フィードの応答
成功時の更新フィードの応答

リスト 18 に示すように、正しいフォーマットが返されると、handleFeedConent 関数は、メッセージ「Operation successful」および正しく挿入された行数を表示します。また、この関数は actionSuccessful イベントも起動します (「ウィジェットの定義ファイル 」セクションで前述したように、このイベントは iWidget.xml ファイルで静的に定義されています)。

リスト 18. フォーム送信の成功
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    resultHTML += "Operation successful.";
    resultHTML += rowCount;
    resultHTML += " record(s) changed.";

    this.iContext.iEvents.fireEvent("actionSuccessful", null, "" );
    ::::::::::::::::::::::::::::::::::::::::::::::::::

リスト 19 に示すように、MashupCenter Relational (JDBC) プラグインがエラー (-1) を返すと、handleFeedConent 関数は systemmsg 要素内に返されたメッセージを使用して、結果ストリングを生成します。また、この関数は actionFailed イベントも起動します。このイベントは、iWidget.xml のイベント仕様 で定義されています。

リスト 19. フォーム送信の成功後に返されるエラー・メッセージ
handleFeedContent: function(data){
    ::::::::::::::::::::::::::::::::::::::::::::::::::
    if (  rowCount ==  "-1" ) {

       var  msg     = "Unknown error. <br><br>";
       var  msgList = dojo.query( "systemmsg" , data );
       if ( msgList  &&  msgList[0] )
            msg = dojox.xml.parser.textContent( msgList[0] );
       resultHTML += msg;

       this.iContext.iEvents.fireEvent("actionFailed", null, rowCount );

フォーム・データ送信中のエラー処理

リスト 20 に示すように、フォーム・データの送信が失敗すると、handleErrorResponse 関数は displayResult を呼び出すことにより、通信の失敗から返された結果を表示します。

リスト 20. handleErrorResponse 関数
handleErrorResponse: function(data)
{
    this.debugTrace( "handleErrorResponse entered data="  + data );
    this.displayResult( data );
}

フォーム送信結果の表示

フォームの送信が成功した場合または失敗した場合のどちらも、displayResult 関数を使用して、フォーム・サイズの記憶、現在の入力フォームの非表示、およびフォーム送信結果の表示が行われます。

resultNode の style は、iWidget.xml 表示モード・レイアウト で初期状態として display:none として定義されており、これによって非表示になります。リスト 21 に示すように、displayResult 関数が style.display 定義を block に変更することにより、resultNode が表示されます。

リスト 21. displayResult 関数
displayResult: function(data)
{
    // save the current size
    var  formSize = dojo.contentBox( this.formDivNode );
    // hide the form
    this.formDivNode.style.display = "none";

    // show the result
    this.resultNode.style.display = "block";
    dojo.contentBox( this.resultNode, formSize );
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = data;
},

resultdiv には、showFromAndHideResult 関数を呼び出す「戻る」リンクが含まれています。リスト 22 に示すように、この関数は resultdiv を隠し、再びフォームを表示します。

リスト 22. showFormAndHideResult 関数
//Clear data, hide the result node, and show the form again.
showFormAndHideResult: function()
{
    this.debugTrace( "handleFeedContent entered" );

    this.formDivNode.style.display = "block";

    // clear any message text
    var resultXmlNode = dojo.byId(this.uid + 'ResultXML');
    resultXmlNode.innerHTML = "";
    this.resultNode.style.display = "none";
},

すべてを組み合わせる

これで、「サンプル・シナリオ」セクションで説明したサンプルのマッシュアップ・アプリケーションに、HTML フォーム・ウィジェットを組み込む準備が整いました。まず、ポリシー・レコード用の HTML フォーム・フラグメントから始めましょう。リスト 23 に示すように、HTML 表を使用してテキスト・ボックスを整理します。前述のように、フォームは Dojo Dijits を使用する必要があります。通常の HTML ページと同様に、フォームの入力フィールドは、リレーショナル更新フィードで使用されるパラメーターと同じ名前を持たなければなりません。フィードは、前の「JDBC フィードの作成」セクションで作成しました。フォームには、INSERT、UPDATE、または DELETE という各アクションの任意の組み合わせに対応する複数のボタンを配置できます。拡張がさらに可能であることを説明するために、対応するフィードを持たず、「Delete Policy」というラベルで機能しない予備のボタンがフォームにあります。

リスト 23. 「ポリシー」 HTML フォーム
<form dojotype="dijit.form.Form" style="font-size:1.3em;">

  <div style='background-color:#D1EACC; height:4em; padding-top:5px; padding-bottom:5px'>
      <center><h3>Policy Address Update and Delete Form</h3></center>
  </div>

  <br>
  <table>

  <tr><td>Policy Id:</td>
      <td><input type="text"  name="policyid"  dojotype="dijit.form.TextBox"
                 style="width: 6em;" readonly /></td>
      <td></td>
      <td></td>
  </tr>

           :::::::::::::::::::::::::::::::::::::::::

  <tr>
  <td></td>
  <td colspan='4' align='right'>
      <button dojotype="dijit.form.Button" value="formUrl1">Update Address
              onclick="_${widgetId}_iContext.iScope().submit('formUrl1');"
      </button>
      <button dojotype="dijit.form.Button" value="formUrl2">Delete policy</button>
  </td>
  </tr>
  </table>
</form>

それでは、図 7 に示すように、「htmlForm 編集」ダイアログに移動し、HTML フォーム・フラグメントを「フォーム Html」フィールドに貼り付け、「JDBC フィードの作成」セクションで作成したリレーショナル・フィードを、対応するフォーム・メソッド・フィールドに貼り付けます。「保存」をクリックし、ウィジェットの構成を完了します。

図 7. 「htmlForm 編集」ダイアログ
「htmlForm 編集」ダイアログ
「htmlForm 編集」ダイアログ

DataViewer ウィジェットで 1 つの行が選択されると、すべての入力フィールドが生成されます。「イベントの処理と生成」セクションで述べたように、HTML フォーム・ウィジェットは、フォームの各入力フィールドに対して受信イベントを動的に作成します。必要なのは、これらのイベントを DataViewer の送信イベントにワイヤリングすることだけです。生成された受信イベントの 1 つから、DataViewer ウィジェットの対応するイベントへのワイヤリングを図 8 に示します。

図 8. 受信イベントのワイヤリング
受信イベントのワイヤリング
受信イベントのワイヤリング

最後に、HTML フォーム・ウィジェットからのactionSuccessful イベントを URL カスタマイザー・ウィジェットにワイヤリングする必要があります。URL カスタマイザー・ウィジェットは DataViewer ウィジェットにワイヤリングされ、DataViewer によって使われる URL と同じ URL を使用するよう構成されます。図 9 に、URL カスタマイザーとワイヤリング・グラフを示します。

図 9. URL カスタマイザーとワイヤリング・グラフ
URL カスタマイザーとワイヤリング・グラフ
URL カスタマイザーとワイヤリング・グラフ

更新オペレーションが成功すると、イベントが起動され、DataViewer が自動的に更新されます。サンプルの更新オペレーションは DataViewer の表示内容を変更しないため、これはこのサンプルにのみあてはまる説明です。

図 10. 送信イベントのワイヤリング
送信イベントのワイヤリング
送信イベントのワイヤリング

まとめ

この記事では、動的イベントの登録やサーバー通信を含む、ウィジェットを作成する基本的な手順を説明してきました。この記事で理解した内容を拡張すれば、リレーショナル更新フィードへの詳細なエラー処理を用いて、ウィジェットを強化できるでしょう。

マッシュアップ・アプリケーションは、さまざまなソースからの情報を表示するダッシュボードとしてよく使われています。このウィジェットにリレーショナル更新フィードを組み合わせることにより、レポートを生成するだけでなく、シンプルな更新アクションが可能なマッシュアップ・アプリケーションを迅速に構築できます。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Lotus
ArticleID=604516
ArticleTitle=マッシュアップ、レポートを超える機能
publish-date=01072011