目次


DB2をバックエンドとしたDelphiでのWebサービスの構築

Comments

はじめに

BorlandTM社のDelphi®およびKylix®が提供する数ある機能の中で、他のビジュアル開発ツールと一線を画するものは、XML Webサービス用のサーバーおよびクライアント・アプリケーションの開発に対する広範かつ総合的なサポートです。DelphiのWebサービス・サポートは、Webサービスのインプリメンテーション用として広く普及しているテクノロジーであるSOAP (Simple Object Access Protocol) をその基礎としています。(SOAPの詳細は、http://www.w3.org/TR/SOAP/を参照。)

Webサービスは、企業間 (B2B) アプリケーションへと大勢が移り変わる原動力となった主要テクノロジーです。このテクノロジーを理解して活用できるように、DelphiとバックエンドのIBM® DB2® Universal DatabaseTMからデータを提供するテスト・クライアントとで作成されている実用的なWebサービスの例を紹介します。

DelphiでのWebサービスの作成

Borland社が最初にWebサービス・サポートを開始したのは、Delphi 6でした。他の方法とは異なり、このテクノロジーは開発環境だけでなく言語自体にも統合されています。かなり以前から、Delphi言語には、Java?の概念によく似た「インターフェース」という考え方が反映されています。今回、Borland社では、インターフェースに対するイントロスペクションのサポートを取り入れました。これにより、インターフェースの公開とリモート起動のための汎用的なメカニズムが実現しています。これは、特にSOAPマッピング層に適合するように調整されていて、そのまま使えるいくつかのコンポーネントがあります。

以上が簡単な背景ですが、次に、Delphi 7でWebサービスを実際にどのように作成するかを説明します。Delphi IDEで、[File] → [New] → [Other] というメニュー・コマンドを使用して新規プロジェクトを作成し、[New Items] ダイアログ・ボックスの [WebServices] タブに移動し、[SOAP Server Application] を選択します。

Webサービスは、通常はWebサーバー拡張機能として配備されるため、使用アプリケーションに最適のWebサーバー・アーキテクチャーが何であるかを判断する必要があります。Delphiでは、Apacheモジュール (もちろんKylixでも使用可能)、CGI、ISAPI (Microsoft IIS Serverを使用するWindowsR上のみで使用可能)、および内部的なWebアプリケーション・デバッガーという選択肢の中から選べます。最初に知っておくべきことは、ここで選択したことがその後のすべてを左右することにはならないということです。ここでの選択は、メイン・プロジェクト・ファイル内のいくつかのコード行に影響しますが、Webサーバー拡張機能またはWebサービスの実際のコードの開発にはほとんど影響ありません。実際、Delphi WebBrokerアーキテクチャーでは、実際に使用されるテクノロジーからサーバー側プログラムの開発を抽出します。新しいプロジェクトを作成し、既存アプリケーションのソース・コード・ファイルをすべてこのプロジェクトに追加するだけで、モデル間を自由に移動できます。

この記事では、Webアプリケーション・デバッガー・モデルを使用します。このモデルは、ソケット接続を使用してカスタムWebサーバーからアクティブにされるスタンドアロンの実行可能ファイルです。Webアプリケーション・デバッガー・アプリケーション自体は、呼び出しをトレースし、アプリケーションのHTTP要求および応答をモニターするためのものです。この記事で説明されているサーバーをテストするには、このプログラムを実行する必要があります。このテクノロジーを使用する利点は、Delphi IDEからサーバー・アプリケーションを実行し、そのアプリケーションのデバッグをすぐに開始できるということです。Webサーバーの拡張ライブラリーのデバッグに必要な煩雑な作業を省けます。

Webサーバー・アーキテクチャーを選んだ後は、Webサービスのインターフェースを作成するかどうかをDelphiに指示します。ここでは「Yes」ボタンをクリックして、インターフェース・ウィザードを起動します。このウィザードに、作成するインターフェースの名前とインターフェースを保存するファイルの名前を入力します。このウィザードは、Webサービスに適したアーキテクチャーの作成を支援するものなので、ウィザードを使う方が賢明です。

Webサービス・アプリケーションの構造

以上の手順が終了すると、DelphiはWebサービス用プロジェクトの完全な構造を生成します。この構造には以下が含まれます。

  • いくつかの標準コンポーネントをホストするSOAPデータ・モジュール
  • SOAPサーバーとして公開されるDelphiインターフェースの定義を含むインターフェース・ユニット
  • 公開するインターフェースのメソッドをインプリメントするためのインプリメンテーション・ユニット
  • 完全なWindowsアプリケーションであるWebデバッガー・アーキテクチャーに基づいたサーバーを表すフォーム。フォームは開発専用なので、今回は無視します。

これでDelphiによりコードが生成されたので、次はWebサービスの開発に取りかかります。最初のステップは、インターフェースのメソッドの定義です。これはWebサービスの機能の定義を意味するものであるため、これが核になるステップです。このステップを進めるにあたり、2つの方法があります。1つは、既存のWSDL (Webサービス記述言語) ファイルを利用し、これをインポートして適切なDelphiインターフェースを生成する方法です。この記事の例ではこの方法を使用します。2つ目は、Delphiコードでインターフェースを定義し、デフォルトでWebサービス・データ・モジュールに追加されるコンポーネントの中の1つ (WSDLHTMLPublishコンポーネント) により、DelphiインターフェースをパブリックWSDLに変換する方法です。

Webサービス・インターフェースの定義とWSDL

この例では、会社の社員に関するデータを公開できるWebサービスを作成します。このWebサービスは、DB2に含まれているSAMPLEデータベースのEMPLOYEE表にマップされます。このWebサービスのDelphiインターフェースを、次のようにSoapEmployeeIntfユニットに定義します (ソース・コードのSoapEmployeeIntf.pasファイルを参照)。

type
  ISoapEmployee = interface (IInvokable)
    ['{77D0D940-23EC-49A5-9630-ADE0751E3DB3}']
    function GetEmployeeNames: string; stdcall;
    function GetEmployeeData (EmpID: string): string; stdcall;
  end;

このユニットには、インターフェースをアプリケーション内の内部SOAPレジストリーに登録する内部初期化コードも含まれています。このインターフェースを作成すると、Webサービス・アプリケーションによりWSDLファイルが生成され、ブラウザーを使用してWebサービスに接続したときに、図1のように、Webサービスの説明が最初のページに表示されます。

図1.ブラウザー経由でWebサービスに接続したときに表示されるWebサービスの説明。1回クリックするだけで、このWebサービスのSOAPインターフェースを説明するWSDLファイルをダウンロードできる。
図1.ブラウザー経由でWebサービスに接続したときに表示されるWebサービスの説明。1回クリックするだけで、このWebサービスのSOAPインターフェースを説明するWSDLファイルをダウンロードできる。
図1.ブラウザー経由でWebサービスに接続したときに表示されるWebサービスの説明。1回クリックするだけで、このWebサービスのSOAPインターフェースを説明するWSDLファイルをダウンロードできる。

別ユニットのSoapEmployeeImplが、次のクラスを使用したこのインターフェースのインプリメンテーションを提供します。

type
  TSoapEmployee = class(TInvokableClass, ISoapEmployee)
  publicfunction GetEmployeeNames: string; stdcall;
     function GetEmployeeData (EmpID: string): string; stdcall;
  end;

これを見てわかるように、このクラスは、DelphiライブラリーのTInvokableClassを継承するクラスで、先に定義したインターフェースをインプリメントします。このWebサービスの実際のインプリメンテーションには、上記の2つのメソッドと、返されるXMLデータを管理するいくつかのヘルパー関数が含まれます。

DB2データベースのアクセス

dbExpressTMアーキテクチャーは、DB2データベースへのアクセスを提供します (詳細は、このサイトに掲載されているBob Swart氏の記事を参照してください)。本記事の例では、データセットは1回読み込むだけで済むので、何もキャッシュせずに1方向データセットを使用しても安全であるという点が、Swart氏の説明とは異なります。

すべての接続とSQLは、次に示すDFMファイルにより定義されるデータ・モジュール (非ビジュアル・コンポーネントのコンテナー) にホストされます (以下のリストには主な要素だけを示してあります)。

object DataModule3: TDataModule3
  object SQLConnection: TSQLConnection
    ConnectionName = 'DB2Connection'
    DriverName = 'DB2'
    LoginPrompt = False
    Params.Strings = (
      'Database=SAMPLE'
      'User_Name=***'
      'Password=***')
    VendorLib = 'db2cli.dll'
  end
  object dsEmplList: TSQLDataSet
    CommandText = 'select EMPNO, LASTNAME, FIRSTNME from EMPLOYEE'
    SQLConnection = SQLConnection
    object dsEmplListEMPNO: TStringField
    object dsEmplListLASTNAME: TStringField
    object dsEmplListFIRSTNME: TStringField
  end
  object dsEmpData: TSQLDataSet
    CommandText = 'select * from EMPLOYEE where EmpNo = :id'
    Params =  <
      item
        DataType = ftFixedChar
        Name = 'id'
        ParamType = ptInput
      end>
    SQLConnection = SQLConnection
  end
end

このデータ・モジュールには、SQLDataSetコンポーネントによりホストされるSQL照会が2つ含まれています。1つ目は、各社員の名前とIDを取り出し、2つ目は特定の社員のデータ・セット全体を返します。ただし、ここで、このデータをリモート・クライアント・プログラムにどのように返すかという問題に直面します。この例では、複雑なSOAPデータ構造を操作するのではなく、XMLドキュメントを返しています。

XMLへの変換

この例のGetEmployeeNamesメソッドは、社員の姓と名を値とし、関連データベースIDを属性として持つ社員のリストを含むXML文書を作成します。ヘルパー関数MakeXmlStrおよびMakeXmlAttributeのコードは省略しましたが、このコードはこの記事をダウンロードして使用できる完全なソース・コードの中に含まれています。

function TSoapEmployee.GetEmployeeNames: string;
var
  dm: TDataModule3;
begin
  dm := TDataModule3.Create (nil);
  try
    dm.dsEmplList.Open;
    Result := '' + sLineBreak;
    while not dm.dsEmplList.EOF do
    begin
      Result := Result + '  ' + MakeXmlStr ('employee',
        dm.dsEmplListLASTNAME.AsString + ' ' +
        dm.dsEmplListFIRSTNME.AsString,
        MakeXmlAttribute ('id', dm.dsEmplListEMPNO.AsString)) + sLineBreak;
      dm.dsEmplList.Next;
    end;
    Result := Result + '';
  finally
    dm.Free;
  end;
end;

2つ目のメソッドのGetEmployeeDataは、パラメーターを使用する照会を使用し、結果のフィールドを個別のXMLノードにフォーマットします (著者が作成し、ここには記載していないヘルパー関数のFieldsToXmlを使用します)。

function TSoapEmployee.GetEmployeeData(EmpID: string): string;
var
  dm: TDataModule3;
begin
  dm := TDataModule3.Create (nil);
  try
    dm.dsEmpData.ParamByName('ID').AsString := EmpId;
    dm.dsEmpData.Open;
    Result := FieldsToXml ('employee', dm.dsEmpData);
  finally
    dm.Free;
  end;
end;

主要な部分以外の詳細コード (Delphiおよびそのクラス・ライブラリーに関する知識のない読者には興味のわくものかも知れません) は割愛しましたが、これでWebサービスのサーバー側コードは完成です。SOAP関連のコードがどこにあるかと疑問に思われるかも知れませんが、どこにもないというのが答えです。WSDLに関して前述のように、Delphiは、ウィザードがSOAPデータ・モジュールに入れた2つのコンポーネント (HTTPSoapDispatcherとHTTPSoapPascalInvoker) を使用して、SOAPエンジンを自動的に提供するのです。

テスト・クライアントの作成

以上でWebサービスが立ち上がって実行可能になったので、次はサーバーと通信するクライアントを作成します。これは、通常、Webサービスを定義するWSDLファイルをインポートして行います。この記事の場合は、受け取るXMLデータを、より管理しやすいものに変換する必要があります。そこで、DelphiのXMLMapperを使用して、Webサービスから受け取る社員リストを、DBGridを使用してビジュアルに表示できるデータセットに変換しました。XMLMapperはどちらかというと複雑なツールであり、この記事では紙面の都合上XMLMapperに関しては触れません。ここでは、この記事のソース・コードに含まれているクライアント・プログラム (図2) を使用します。Delphiを使用したSOAPクライアント・アプリケーションの作成方法は、今後の記事で詳しく説明します。

図2. Webサービスのテストに使用するクライアント・プログラム
図2. Webサービスのテストに使用するクライアント・プログラム
図2. Webサービスのテストに使用するクライアント・プログラム

まとめ

この記事では、DelphiでWebサービスを作成し、DB2データベースに接続してデータを取り出すことがいかに容易かを説明しました。ここではXMLを生成しただけです。データベース・データをXMLにマッピングするためにDelphiがサポートしている技法は多数あり、それをすべて説明したわけではありません。記載した例では、XMLを直接生成してあります。特記すべきことは、ここで作成したプログラムはLinuxサーバーに完全に移植可能であるということです。これには、このプログラムをKylixを使用して再コンパイルし、デバッグ・バージョンからApacheモジュールに変換します。この分野で説明すべきことはまだ多数あります。今後も関連記事に注意していてください。


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


関連トピック


コメント

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Information Management
ArticleID=322958
ArticleTitle=DB2をバックエンドとしたDelphiでのWebサービスの構築
publish-date=12052002