メニューボタン
IBMi海外記事2010.12.06

PHPとRPGのWebサービスの実装

Erwin Earley 著

PHPでRPGアプリをWebサービスとして利用したり、RPGでPHPアプリを Webサービスとして利用する

過去の掲載記事では、IBM i における PHP、またPHP を使用してDB2 データ、データ域、データ・キューなどの IBM i リソースをコンテンツとして活用しているダイナミック・コンテンツと結合した Web アプリケーションをどのように開発するかを中心に説明しました。また、IBM i ショップがオープン・コミュニティーを利用した幅広いアプリケーションを展開できるよう、PHP と MySQL がどのように協力できるかについての記事もありました。今回は、Web サービスに焦点を当て、PHP を使用して RPG アプリケーションを Web サービスとして利用する、また逆に RPG を使用して PHP アプリケーションを Web サービスとして利用する方法をご説明します。

Webサービスについて

Web サービスとは、ネットワーク (通常は WAN) で相互運用可能なマシン間対話をサポートするよう設計されたソフトウェア・システムと定義できます。Web サービスは Web サーバー経由でネットワークに公開されており、契約に基づきサービスを利用するクライアントへサービスを提供しています。Web サービスではサーバーとクライアント間でデータを交換する際に、両方のシステムが互いに認識できるよう、標準 XML 形式を使用して要求とデータをパッケージ化しています。Web サービスは、顧客の残高を確認したり、口座を新規開設するといった反復性のある業務の代表といえます。

Web サービスにはさまざまな利点がありますが、中でも、インターネット経由でアプリケーションを共有して、データおよび機能の集中型アクセスを実現したり、情報やロジックをネットワーク上のオブジェクトとして共有するという利点があります。実際、Web サービスに何ら目新しいところはありません。RSS フィードを使用してニュースを別の Web サイトから取り出し、自分のサイトに配置したことがあるユーザーなら、Web サービスの動作はよく理解していることと思います。Web サービスは、サービス指向アーキテクチャー (SOA) の中核をなすものです。このアーキテクチャーにより、ビジネスはリンク・サービスとして統合されます。

今日のインターネットの世界では、Web サービスは、ネットワーク上でアクセスし、要求されたサービスをホストしているリモート・システムで実行できる API の集合と捉えるケースが多くなっています。一般的に、サービスを要求しているシステム (つまり、サービス利用者) をクライアントと呼び、サービスを保持 (公開) し、実行するシステムをサーバーと呼びます。クライアントとサーバーは HTTP 経由で互いに通信します。Web サービスも、ブラウザーが HTML 形式をサイトに POST し、応答として Web ページを受信する場合と実質的に同じように動作します。Web サービスでは HTML ではなく XML を使用する点だけが違います。つまり、Web ページの参照プロセス時と同様にファイアウォールを通過して、Web サービスはインターネット上ならどこででも利用できるということです。クライアントとサーバー間のデータ交換はパッケージ化層で行われます。

通常、サービスは Simple Object Access Protocol (SOAP) と Representational State Transfer (REST) の 2 種類のカテゴリーに分けられます。この記事では、以下のような特性を持つ REST スタイルを中心にお話します。

  • 状態と機能が分散リソースに分かれている。
  • 均一化した最小限のコマンド・セットを使用 (通常は、インターネットで GET、POST、PUT、または DELETE などの HTTP コマンドを利用) して、どのリソースも一意にアドレス可能である。
  • プロトコルはクライアント/サーバー、ステートレス、階層化型で、キャッシングをサポートしている。

REST スタイルで問題になるのがロケーションで、ここでは、ブラウザー・セッション内の REST ロケーションは、 REST クライアント・プログラムをクリックするか、URL ロケーションに基づきページやサービスを呼び出すことでアクセスできます。最も手際が良い REST Web サービスでは、「従来の XML」(POX) を使用して、クライアントとサーバー間でデータ通信が行われます。REST/POX は、クライアント・プログラム間で XML を渡すことを指す場合が多いです。

モジュラー化する: モデル・ビュー・コントローラー

ある意味では、Web サービスのパワーは、全機能型 Web ブラウザーから PDA、携帯電話、スマートフォンなど、さまざまなエンド・ユーザー・デバイスのコンテンツ、機能、アプリケーションを活用することから生まれてきます。多数の情報システムは、データ・ストアからデータを取得し、そのデータをユーザーに表示し、データを変更した後にデータ・ストアに更新内容を戻すことができるようにする目的で作成されています。従来の開発者は、コーディング量を減らし、アプリケーション・パフォーマンスを向上させるため、UI とプロジェクトのデータ操作 (取得/更新) 機能部分を結合したいと考える傾向がよくありました。

今日のような Web 中心の世界では、UI は、アプリケーションのデータ・ストア部分と比較しても、はるかに変更される頻度が高くなる傾向にあります。私がそれとなくお話したように、新しいエンド・ユーザー・デバイスはかつてない早いペースで登場し、既存のデバイスも頻繁に更新されています。ビジネス・アプリケーションのデータとエンド・ユーザー・インターフェースを結合すると、アプリケーションのデータ転送 (または表示) をはるかに超えるビジネス・ロジックを取り込むことになります。優れた設計パラダイムに固執することが、コンピューター・ソリューションの構造を変更する段階になったときに大きな価値を持つことになります。モデル・ビュー・コントローラー (MVC) などの設計パラダイムや Web サービスの活用は、豊富な機能でダイナミック・コンテンツを活用すると同時に、素早い開発モデルに対応したアプリケーションの開発と展開に大きな役割を果たします。

Web 指向のアプリケーションを開発する際は、多数の問題があることを考慮する必要があります。UI はビジネス・ロジックよりも頻繁に変更される傾向があります。アプリケーションは、例えば、全機能型 Web ブラウザーで表示されるデータとスマートフォンで表示されるデータなど、同じデータでも異なる形式で表示することができます。視覚的に魅力的で効果的な HTML ページの設計と開発には、複雑なビジネス・ロジックの開発とは異なるスキルが必要になります。

UI 内で行われるアクティビティーは通常、データ・ソースからデータを取得し、表示できるようデータをフォーマットする「プレゼンテーション」と、制御をビジネス・ロジックに戻して、データに対するユーザー処置に基づいてデータを更新する「更新」の 2 つの部分で構成されています。最後に、UI コードはビジネス・ロジックよりもデバイスに依存する傾向があります。例えば、アプリケーションをブラウザー対応から PDA や Web 対応携帯電話をサポートできるように移行するには、UI コードの大部分を置き換える必要があります。一方ビジネス・ロジックには、これら種類の異なるデバイスをサポートする場合でも変更する必要がないケースが多々あります。ビジネス・ロジックと UI を明確に分けることができることでマイグレーションが促進され、ビジネス・ロジックで誤りが発生する危険性が最小限に抑えられます。

図 1 に図示した MVC の設計パターンでは、ユーザー入力によるドメイン、プレゼンテーション、アクションのモデル化が以下の 3 つの別々のクラスに分けられます。

  • アプリケーション・ドメインの動作とデータを管理する「モデル」は、(通常はビューからの) 情報とその状態に対する要求に応え、(通常はコントローラーから) 状態を変更する命令に応答します。
  • 「ビュー」は情報の表示を管理します。
  • 「コントローラー」は、ユーザーからのマウスとキーボード入力を解釈し、適宜、モデルまたはビューに変更するよう通知します。

効果的な設計パラダイムを作成すれば、ビュー (UI) を簡単に置換えたり、展開できるよう、インターフェースからデータ層を分離できます。MVC では、すべてのビューがデータのオブザーバーであるため、モデル・データの変更は、すべてのインターフェースに反映されます。UI とアプリケーション・ロジックが分離されているため、このタイプの設計パラダイムは、より優れたスケーラビリティーをサポートし、さらにネットワーク上で簡単に配布できるようにします。これは Web サービスのもう 1 つの重要な側面です。MVC は、ビジネス・ロジックの変更によるプレゼンテーション層の破損の可能性を減らし、逆に、プレゼンテーション・ロジックの変更によるビジネス・ロジックの破損の可能性を減らすことで、メンテナンスの負荷を軽減する場合に役立ちます。さらに、MVC は多目的チーム開発というアプローチを推進しています。これにより開発者は、UI の破損を気にせずに堅固なビジネス・コードを作成することに集中でき、設計者は、ビジネス・コード開発に使用する言語を気にせずに便利で魅力ある UI を構築することに集中できるからです。MVC では、ビジネス・ロジックの作成には RPG、UI の作成には HTML を使用するなど、開発プロセスの側面ごとに最適なツールを簡単に使用することができます。

RPG *SRVPGM を PHP から Web サービスとして利用する

Web ブラウザーを通してユーザーと IBM i アプリケーションを接続する端末エミュレーター (図1) のユーザーは依然として多少存在しますが、一般的に現在のユーザーには向いていません。さらに、エミュレーターはほとんどの人にとって扱いにくいようです (さあ、私はこう言いました)。開発者としてエミュレーターが好みなら、それは素晴らしいことです。ただ、誰もが好んでいるとは思わないでください。そうしたことを念頭に、いくつかとんでもない誤解を見ていきましょう。

ビジネス・ロジックとプレゼンテーション (または UI) を分離することに重点を置いて設計されたアプリケーションにより、アーキテクチャー全体のさまざまな部分を簡単に交換できるようになります。例として、MVC パラダイムに従って、RPG SRVPGM モデルを Web 対応サービスとして利用するPHP ビューおよび制御エレメントを実装できます。

この例では、まず (Zend Core で提供された) i5 ツールキットから RPG *SRVPGM を呼び出して REST サーバーを実装します。図 2 で示した例中のコードでは、REST サーバーは POX を REST クライアント・プログラムにフィードしています。REST サーバー・コントロールが HTML GET 要求または POST 要求 (_POST 変数) を受け入れている点に注目してください。REST クライアントに戻される「ビュー」は POX (XML) になります。以下のコードにより POX が構築されます。

<?php
function POX_out($search_item)
{ $simple = new SimpleXMLElement('<result></result>');
 foreach($search_item as $it)
 {$book = $simple->addChild("book");
  $dvd->addchild("TITLE",$it[1]);
  $dvd->addchild("AUTHOR",$it[2]);
 }
 Return $simple->axXML();
}

例では、オブジェクト指向 (OO) クラス/オブジェクトを少し使用しており、多少見慣れない新しい演算子やオブジェクト演算子 (->) があるかもしれません。しかし、それでもほとんどプロシージャー型モデルです。SimpleXML は、ストリング連結を処理せずに整形式 XML を構成する理想的な方法を実現しています。

ここで、REST サービスへのクライアント呼び出しをコーディングする必要があります。REST URL (ロケーション) を決定する必要があります。接続コードは、同じサーバーの REST サービスを呼び出す URL「ベース」を生成するはずです。図 3 が示すように、REST サービスに渡される可変パラメーターが REST クライアント・モデル・コードの URL ベースに追加されます。

REST サービスは通常、予約済みアドレス (例: http://yahoo.com/REST/Service) です。この例では、PHP superglobals からの情報を使用して URL を計算し、$MODEL['conn'] 変数に配置しています。初期ドメインが決定したら、図 4 に示すように、特定の要求パラメーターが HTML GET 形式で REST サービスに付加されます。このコードにより、REST サービスの呼び出しに使用できる、パラメーターを指定した完全に整った URL が作成されます。

http://myi5:89/RestServer.php?type=fiction&limit_num=4

これで PHP API を使用して REST サービスからデータを「GET」できます。この例では、simplexml_load_file(「URL」) を使用して REST サーバーからの POX (XML) を簡単にしています。

// get the REST XML document
$xml = simplexml_load_file($link_id);
if (!$xml)
{ model_error("simplexml_load_file($link_id) failed");
  return False;
}

POX (XML) を受信したら、図 5 に示すように SimpleXML を使用して POX (XML) を構文解析し、見つかった検索項目の配列を返すだけです。

PHP アプリケーションを RPG から Web サービスとして利用する

PHP から RPG を呼び出すことが可能なだけでなく、RPG から PHP を呼び出すこともできます。これは、Zend Core (/usr/local/Zend/Core/bin/php-cli) で提供されるコマンド行インターフェース (CLI) を利用して実現できます。PaseExec32 経由で RPG から渡される PHP コマンドは、コマンド行に入力されるコマンドとまったく同じですが、PHP スクリプトからの出力は以下の PaseExec32 呼び出しに提供された RPG 変数で収集される点が異なります。

ind = PaseExec32(cmd:paseStdOut);

これは、PASE の popen API を使用してポータブル・アプリケーション・ソリューション環境 (PASE) に重労働をさせるという考えに基づいています。popen API は、呼び出し側プログラムと実行するシェル・コマンド間のパイプを作成します。実際は popen は 5250 コマンド行から qp2term を呼び出した場合と同じ動作をしますが、コマンドの標準出力 (stdout) が RPG プログラムにリダイレクトされる点が異なります。popen API はシェル・コマンドの実行のみを目的にしている点を覚えておいてください。無効なシェル・コマンドを実行しようとすると、予測できない結果になります。

コマンドを実行する能力を提供する、また出力を呼び出し元に戻すための重要な PASE API が多数あります。これらの API は、無数の AIX プログラムで使用される共通 UNIX API を提供するライブラリーである libc.a で提供されます。以下のような API がそれに該当します。

  • popen("cmd", "r"): 新しいプロセスを fork し、指定のコマンドを実行して、標準出力を収集します。
  • Fgets: 出力をバッファーに格納します。
  • Pclose: popen で開かれていたプロセスを閉じます。

まず、Qp2RunPase API を使用して PASE メイン・プログラムを呼び出し、RPG プロセスから PASE を呼び覚まします。呼び出しには、パラメーターと環境変数が指定されています。

/usr/bin/start32 - start 32 bit PASE

通常、PASE メイン・プログラムを Qp2RunPase API で呼び出すと PASE が目覚め、プログラムを実行し、PASE メイン・プログラムが RPG 呼び出し元に戻ったときに PASE 環境を終了します。start32 ユーティリティーは、特殊な PASE 戻り API (_RETURN) を備えたメイン・プログラムで、start32 プログラムが PASE を目覚めさせ、PASE 環境を終了せずに RPG 呼び出し元に制御を戻すことができるようにします。これにより、libc.a などの PASE の共有ライブラリーにアクセスできるようになり、start32 メイン・プログラムが実質的に完了していても PASE 関数をそれぞれ呼び出すことができます。

別の PASE API である Qp2dlopen により、PASE メイン・プログラムが担当しているかのように、RPG プログラムから、使用する任意の PASE 共有ライブラリーをロードすることができます。以下の点を念頭に置いてください。Qp2RunPase('/usr/lib/start32') は 32 ビット PASE プロセスを呼び覚まし、キープアライブします。Qp2dlopen(*NULL) は共通 PASE 共有ライブラリーへのハンドルを提供します。これら 2 つは自ら呼び出し、自ら著しい数の PASE 関数を開いて、RPG プログラムで使用できるようにします。

Qp2RunPase('/usr/lib/start32') を呼び出して PASE を呼び覚ましてもシャットダウンはしないため、終了したら PASE を終了させる別の呼び出しが必要になります。これは Qp2EndPase() API を使用して実現します。この API は RPG ジョブから PASE を削除します。Qp2EndPase を呼び出す前に PASE 関数の処理が終了するようにしてください。RPG プログラムから引き続き PASE を使用しようとすると失敗し、Qp2RunPase への介入呼び出しによりプログラムの動作が遅くなるためです。

ともに作業の質を高める

この記事で、PHP と RPG を統合して、それぞれの利点を考慮して両方の言語を活用できるようにする方法の実態が、多少でも改めておわかりになったかと思います。この記事を含めた私の記事についてのご質問やご意見を opensolutiosn@askerwin.com まで送っていただけば幸いです。

あわせて読みたい記事

PAGE TOP