ILE RPGプログラムをREST webサービス化する。
もしくは、ILE RPGから外部のAPIへダイレクトに接続する。
IBM iをWatsonのAPIサービスに接続するこの2つのアプローチについて詳しく紹介しよう。
中村陽一 氏
日本アイ・ビー・エム システムズ・エンジニアリング株式会社
クラウド・アプリケーション
アドバイザリーITスペシャリスト
ILEプログラムを
REST webサービス化して接続
IBM iの定型データと非定型データを融合させ、新たなビジネス価値を生み出す。それにはどのような方法があるのだろうか。
IBM iが外部のAPIサービスなどと連携するには、大きく2つのアプローチがある。1つはIBM iのプログラム(ILE RPGなど)をREST webサービス化し、外部のアプリケーションから接続すること。もう1つはIBM iのILE RPGなどから、外部のAPIに接続することである。
言い換えれば、アプリケーションの中心をIBM iの外部に置くか、IBM iの内部に置くかによってアプローチが異なる。本稿ではこれら2つの連携手法について詳しく解説しよう。
IBM iは、「統合Webサービス・サーバー」と呼ばれる機能を備えている。これは、ILEプログラムおよびサービス・プログラムをREST webサービスとしてデプロイする機能である。これにより、慣れ親しんだILEプログラムで基幹データにアクセスし、5250アプリケーションで利用すると同時に、Webや外部アプリケーションへ簡単に展開できる。
統合Webサービス・サーバーでのRESTサポートは図表1のとおりで、以下の流れで実装されている。
【図表1】統合Webサービス・サーバーでのRESTサポート
①クライアントサイドのWebサービス・リクエスターから、HTTPリクエストがサーバーサイド (IBM i) に送られる。
②サーバーサイドでは、HTTPサーバーがリクエストを統合Webサービス・サーバーに転送する。
③統合Webサービス・サーバーが、転送されたリクエストをToolbox for Java (JTOpen) のPCML (Program Call Markup Language)に変換してILEプログラムを呼び出す。
④Webサービス・プロバイダーとしてILE RPGが実行され、PCML呼び出しの実行結果を統合Webサービス・サーバーに戻す。
⑤統合Webサービス・サーバーは実行結果を受け取ったあとに、Webサービスのレスポンスとして変換して戻す。
例としてIBM Cloud上にWatson APIを呼び出し、ユーザーと対話するNode.jsアプリケーションを作ることを考えてみよう。Conversationでユーザー入力・会話を判別し、その結果をもとにIBM i上の基幹DBを照会し、結果をText to Speechで応答するようなアプリケーションとなる。この基幹データ照会自体は、IBM i上の基幹システムですでに実装されているとする。この場合、統合Webサービス・サーバーによるREST webサービス化でIBM Cloudから容易にアクセスできるようにするとよい。
このように統合Webサービス・サーバーによるREST webサービス化は、クラウド・アプリケーションやWatson APIとの連携の1つのキーとなる機能だ。ここからは実際にIBM i上のILE RPGプログラムを、統合Webサービス・サーバーを介してREST webサービスとして提供する方法を見ていこう。
今回取り上げるのは、ILE RPGでコーディングされたIBM i上の顧客情報処理サービス・プログラムIMAGPGM/CUSTINFFRをREST webサービス化する手順である。
このサービス・プログラムIMAGPGM/CUSTINFFRには、5つのプロシージャーが定義され、IMAGDB/CUSTOMERテーブルに格納された顧客情報の参照・登録・更新・削除を実行する(図表2)。各プロシージャーのプロトタイプ定義は、図表3のとおりである(CUSTINFFRはフリーフォームRPGで書いているが、もちろん固定フォーマットでも構わない)。
【図表2】CUSTINFFRプロシージャー一覧
【図表3】各プロシージャーのプロトタイプ定義
サービス・プログラム内の各プロシージャーをREST webサービス化する場合、以下の3点を事前に検討する必要がある。
(1)HTTPメソッドの検討
REST webサービス化するILEプログラムの各プロシージャーで、対象データやリソースにどのような操作 (追加・更新・読み取り・削除) を実行しているかを把握し、それに対応したHTTPメソッドを割り当てる。REST webサービスでは、以下のHTTPメソッドを割り当てるのが一般的である。
リソースの読み取り:GET リソースの新規作成:POST
リソースの更新:PUT リソースの削除:DELETE
これらに準拠する形で、どのHTTPメソッドでリクエストが送られてきた場合に、どのプロシージャーを呼び出して動作させるかを決める。
(2)URIの検討
どのURIが指定された場合に、どのプロシージャーを呼び出すかを考える。URIを検討するポイントとしては、「そのサービスが操作対象とするリソース/データを名詞で表現する」(多くの場合、操作対象となるリソース/データにどのような処理を実行するかはURIではなく、HTTPメソッドで判別できるため)、あるいは「容易に推測可能な語句を採用する」などが挙げられる。
(3)入出力に関する検討
各プロシージャーをREST webサービス化した際に、入出力パラメータはどのようなフォーマットや方式で受け渡すのか、出力パラメータにHTTP応答コードやHTTPヘッダーを含ませるかといった項目について、各プロシージャー単位で考える。
今回の顧客情報処理サービス・プログラム内の各プロシージャーについては、以上の3点を図表4のように設定する。顧客情報を処理対象とするので、URIは/customersとし、各プロシージャーの処理内容に応じてGET/POST/PUT/DELETEを定義している。
【図表4】URIと各プロシージャーに対するHTTPメソッドと入出力設定
プロシージャーのGETBYCODEとHTTPメソッドのDELETEは顧客コードを指定して処理するので、入力パラメータとして顧客コードをパスセグメント、URIの一部として受け渡す形式にしている。また処理結果をHTTP応答コードとして出力に含ませる。
統合Webサービス・サーバーに
REST webサービスをデプロイ
ここまで検討したら図表5のように、統合Webサービス・サーバーにREST webサービスをデプロイしよう。デプロイは、以下の2つのフェーズで実行する。
【図表5】統合Webサービス・サーバーへのデプロイ
①ILE RPGプログラムにPCMLを組み込んでコンパイル
PCMLとは、ILEプログラムの入出力を定義したXML形式のデータである。PCMLを用意すると、Toolbox for Java (もしくはJTOpen) で提供されるJavaプログラムからILEプログラムを呼び出す機能を簡単に利用できるようになる。
ILEプログラムの作成時、PGMINFOパラメータに*PCMLを指定することで、IFS上のストリーム・ファイルとしてPCMLを自動生成できる。また、プログラム・オブジェクト自体にPCMLの情報を格納させることも可能である。
プログラム・オブジェクトに格納されたPCML情報を統合Webサービス・サーバーに読み込ませ、REST webサービス化する。PCMLのオブジェクトへの組み込みは、コンパイル・コマンドのオプションのほかに、制御仕様書でも指定できる。今回のCUSTINFFRでは図表6のように制御し、仕様書に指定している。
【図表6】制御仕様書でのPCML生成オプションの指定
②統合Webサービス・サーバーへREST webサービスをデプロイ
次に、統合Webサービス・サーバーへREST webサービスをデプロイする。統合Webサービス・サーバーの管理インターフェースは、「Web Administration for i 」(http://<system>:2001/HTTPAdmin) で提供されており、以下の手順でREST webサービスをデプロイする。
まずWebブラウザで、http://<system>:2001/HTTPAdminにアクセスし、「Web Administration for i」を表示し、「Manage」タブ→「Application Servers」タブから、REST webサービスのデプロイ対象となる統合Webサービス・サーバーを選択する。
さらに画面左側にある「Web Services Wizards」メニューで、「Deploy New Service」をクリックすると、「Deploy New Service」ウィザードが起動する。このウィザードに沿って、以下のように内容を登録していく。
Step 1 Webサービス・タイプの選択
最初のステップでWebサービス・タイプを選択する。統合Webサービス・サーバーではRESTのほかに、SOAP webサービスのデプロイも実行できる。今回はRESTを選択する。
Step 2 ILEプログラムの指定
REST webサービスとしてデプロイするILEプログラムのプログラム名、ライブラリー名、オブジェクト・タイプ (サービス・プログラムか、プログラムか)を指定する。統合Webサービス・サーバーは、ここで指定したプログラム・オブジェクトからPCML情報を自動的に読み込み、プログラムの入出力情報を判別する(図表7)。
【図表7】ILEプログラムの指定
Step 3 URIの指定
先に決定したREST webサービスのURIを指定する。URI path templateにはWebサービスを判別するための正規表現を指定できるが、今回の例では「/customers」とするので、とくに指定せずに「/」となる。
Step 4 入出力データの設定
PCMLを読み込むことで、各プロシージャーの入出力情報が表示される。ILE RPGでのインターフェース定義では、CONST定義されている場合は入力パラメータとして、それ以外は出力パラメータとして表現されるので、各パラメータの実際の入出力定義を指定する。
またGETALLプロシージャーでは、全顧客情報をデータ構造 (customersDs) の配列で返す。ILE RPGでは図表3のプロトタイプ定義のとおり、最大要素数を1000で定義し、実際の顧客情報の件数は別のパラメータ (numOfCustomers) で返す。
ウィザードでも、customersDsの要素数は設定の1000として表示される。この要素数は実数であるnumOfCustomersに変更しておけば、REST webサービスとして応答を返す際に余分なサイズを返さずに済む。この要素数を設定する際には、「Detect length fields」のチェックを外しておく必要がある(図表8)。
【図表8】Webサービスの入出力設定
Step 5 対応するHTTPメソッドの設定
ここではILEプログラムの各プロシージャーに対して、以下を設定する。
・対応するHTTPメソッド
・入力パラメータを受け取る際の形式
・入出力パラメータのフォーマット(JSON形式、XML形式)
・入力パラメータの受け渡しとILEプログラム側のパラメ ータのマッピング設定
・HTTP応答コードやHTTPヘッダーを出力パラメータとして渡す際のILEプログラム側のパラメータのマッピング設定
たとえばCUSTINFFRのREMOVEプロシージャーは、指定した顧客コードの顧客情報を削除するプロシージャーである。REMOVEプロシージャーは、REST webサービスとしてHTTP DELETEメソッドでリクエストを受け取ったとき、URIパス・パラメータとして顧客コードを受け取る。この顧客コードは8桁の数値なので、正規表現で受け取る値の形式を制御している。
また今回は、ILE RPGからHTTPステータス・コード を(プロシージャーによってはHTTPヘッダーも)出力パラメータとして返している。その場合のHTTPメソッドの設定例は、図表9になる。
【図表9】REMOVEプロシージャーのHTTPメソッド設定
各プロシージャーの設定は、図表10になる。UPDATEやREGISTERは、JSON形式で更新内容や登録内容を渡すので、「Allowed input media types」として「*JSON」を指定する。またGETALL、GETBYCODEはJSON形式で照会結果を出力するので、「Returned output media types」で「*JSON」を指定する。
【図表10】各プロシージャーのHTTPメソッド設定
Step 6 ユーザー・プロファイルの設定
IBM i側で、ILEプログラムが動く際のユーザー・プロファイルを指定する。統合Webサービス・サーバーのREST webサービスは、最終的にはPCMLプログラム呼び出しとなるので、IBM i側での処理はホスト・サーバー・ジョブQZRCSRVSとして動く。このジョブの現行ユーザーとして、ここで指定したユーザーが用いられる。今回は「IMAGUSER」というユーザーを指定している。
Step 7 ライブラリー・リストの設定
ユーザー・プロファイルの設定とともに、ILEプログラムが動く際のライブラリー・リストもここで指定する。今回は顧客情報テーブルCUSTOMERが、ライブラリーIMAGDBにあるため、ライブラリー・リストにIMAGDBを追加する。
Step 8 受け渡しメタデータの設定
HTTPヘッダーで受け渡したいメタデータがあれば、ここで指定する。今回の例ではとくに受け渡さないので、そのまま次のステップに進む。
Step 9 サマリーの確認とデプロイ
最後にサマリーを確認する。ここまでの設定内容を確認したあと、Finishをクリックするとデプロイを自動的に開始する。以上で、REST webサービスの設定は完了である。
デプロイが完了すると、「Manage Deployed Services」にリスト表示されるので、ここから開始・終了などを実行できる(図表11)。
【図表11】デプロイされたRESTサービス
統合Webサービス・サーバーにデプロイしたREST webサービスは、デフォルトではコンテキスト・ルートが/web/servicesとなる。今回デプロイしたREST webサービスへのアクセスは、http://<system>:iws-port/web/services/customersとなる。
実際にWebブラウザのRESTクライアントで接続してみよう。今回はFirefoxのアドオンRESTClientを使用しているが、ChromeであればPostmanなどを使って試すとよい。
IBM iへセキュアにアクセスする
Secure Gatewayサービス
ここまでILEプログラムをREST webサービス化する流れを見てきたが、多くの場合、IBM iは基幹システムとして、通常は外部からのアクセスが厳しく制限されたネットワーク環境に置かれている。そのようなIBM iに対してIBM Cloudからアクセスする際に活用できるのが、Secure Gatewayサービスである。
図表12は、IBM Cloud側のアプリケーションから統合Webサービス・サーバーのREST webサービスへ、Secure Gateway経由での連携を示している。IBM Cloud上にSecure Gatewayサービスを構成し、オンプレミス側にSecure Gateway Clientを配置して、両者間にセキュア・トンネルを確立する。
【図表12】Secure Gatewayを用いたIBM Cloudとの連携
これによりIBM Cloud上のアプリケーションから透過的に、IBM iの統合Webサービス・サーバーに展開されたREST webサービスにアクセスできる。
ここで、ILEプログラムのREST webサービス化により実現できるIBM iとWatsonの連携を考えてみよう。IBM iのデータがREST webサービスによって呼び出せるので、フロントエンド側にIBM Cloudや他のサーバーで動作するJavaやNode.jsなどを配置し、Watsonと組み合わせたアプリケーションを作成できる。
たとえば図表13のようにWatson APIの「Conversation」「Speech to Text」「Text to Speech」を使って音声での対話を構成し、図表14のようにIBM iのデータをREST webサービスで呼び出すチャットボットを作れる。
【図表13】IBM iとWatsonとの連携例
【図表14】IBM iとWatsonとの連携アプリ例
IBM iのILE RPGからダイレクトに
外部のAPIへ接続する
次に、外部のAPIサービスをIBM iのILE RPGから呼び出し、IBM i上のアプリケーションで外部サービスを活用するもう1つのアプローチを見ていこう。IBM iでのこれまでの開発スキルを活かし、RPGを中心にしたシステム構築が可能となる。
IBM iアプリケーション側からREST webサービスを呼び出すには、「Db2 for i のHTTPスカラー関数の活用」と「ILE RPGでのTransport APIの活用」の2つの方法がある。
Db2 for i のHTTPスカラー関数の活用
IBM iのデータベース機能 (Db2 for i)はIBM i7.1から、HTTPメソッドを呼び出す以下の8つのスカラー関数をサポートしている。
httpGetCLOB httpGetBLOB httpPostCLOB
httpPostBLOB httpPutCLOB httpPutBLOB
httpDeleteCLOB httpDeleteBLOB
これらはライブラリーSYSTOOLSで提供されており、SQLで利用できる。内部的にはJavaを利用するため、57xxJV1の導入が必要である。使用する場合は、アクセスしたいURLを入力として関数に引き渡し、CLOBないしはBLOBで値を受け取る。またHTTPメソッド単位で関数が定義されているので、適切な関数を指定する必要がある。
たとえば、IBM iインターネット・セミナーで公開されている「IBM i基幹業務データと気象データの連携」(http://ibm.biz/ISWEATHER)では、IBM Cloudの「Weather Company Data サービス」から、httpGetCLOB関数を使って気象データを取り出し、IBM i上の基幹データとともに活用するケースを解説している。
実際にWeather Company DataからhttpGetCLOB関数を使用してアクセスすると、JSON形式で取得できる(図表15)。
【図表15】httpGetCLOBでのREST Webサービスの呼び出し
取得したJSON形式のデータは、Db2 for i のテーブル関数JSON_TABLEを用いて、基幹データと直接結合できる。HTTPスカラー関数とJSON_TABLEテーブル関数の組み合わせにより、REST webサービスで得られる基幹データの活用度は飛躍的に高まるわけだ。
なお図表15の例では、IBM iナビゲーターのSQLスクリプトの実行画面からアクセスしているが、ILE RPGの組み込みSQLからのアクセスも可能である。ILE RPGの組み込みSQL では、SQLデータ・タイプCLOBないしはBLOBのホスト変数に結果を格納する場合、サイズは最大約16MBになる点に注意が必要である。
ILE RPGでのTransport APIの活用
統合Webサービス・クライアントAPIを活用すれば、ILE RPGから直接REST webサービスを呼び出せる。統合Webサービス・クライアントはApache Axisを利用しており、IBM iでは以前より、SOAP webサービスをILEプログラムから呼び出す機能を提供してきたが、REST webサービスを呼び出す「Transport API」という機能が新たに追加された(図表16)。
【図表16】CUSTINFFRプロシージャー一覧
このAPIを利用して、ILE RPGからREST webサービスを呼び出す手順は以下のとおりである。
(1) axiscTransportCreate() を用いてトランスポート・オブジェクトを作成
(2) axiscTransportSetProperty() を用いてHTTPメソッドやHTTPヘッダーといった属性情報をトランスポート・オブジェクトに設定
(3) axiscTransportSend() を用いて送信するデータをバッファに入れる (POSTやPUTで送信データがある場合)
(4) axiscTransportFlush() を用いてHTTPリクエストを送信
(5) axiscTransportReceive() を用いてHTTPレスポンスを受信
(6)axiscTransportDestroy() を用いてトランスポート・オブジェクトを削除
実体は、ライブラリーQSYSDIRにあるサービス・プログラムQAXIS10CCで、これらのAPIのプロトタイプ定義が、
/QIBM/ProdData/OS/WebServices/V1/client/include/Axis.rpgleincとして提供されている。ILE RPGのソースに/COPYで取り込めば、簡単に利用できる。
ここでは図表17のように、前述した顧客情報処理サービス・プログラムCUSTINFFRのREST webサービスを利用し、上記の手順に沿って、別のIBM i上のILE RPGプログラムIMAGPGM/CUSTINFCLからGETBYCODEプロシージャーを呼び出してみよう。
【図表17】ILE RPGからREST webサービスを利用
Transport APIを呼び出すIMAGPGM/CUSTINFCLを作成するには、サービス・プログラムQSYSDIR/QAXIS10CCをバインドする必要がある。CRTRPGMODコマンドでモジュールを作成したあとに、CRTPGMコマンドでQAXIS10CCをバインドするとよい。
今回はより簡潔にするため、バインド・ディレクトリーIMAGPGM/CUSTINFCLを作成し、QSYSDIR/QAXIS10CCを登録しておき(図表18)、制御仕様書で作成したバインド・ディレクトリーを指定する(図表19)。
【図表18】バインド・ディレクトリーの作成とQAXIS10CCの登録
【図表19】制御仕様書でのバインド・ディレクトリーの指定
これによりCRTBNDRPGコマンドでも、QSYSDIR/QAXIS10CCをバインドした状態でプログラムを作れる。またTransport APIを使用するため、提供されているプロトタイプ定義を取り込んでいる。
これでILE RPGがTransport APIを使用する準備が整った。あとは手順に沿って、各Transport APIを呼び出していく。
Transport API を呼び出す
ソースの流れ
プログラムCUSTINFCLでは図表19のように、mainプロシージャーをメイン・プロシージャーとして定義している。ここからはmainプロシージャーのソースを順に追っていくことにしよう。
まず図表20のように、変数uri に今回作成したREST webサービスのURIを指定する。プログラムCUSTINFCLは顧客コードを入力パラメータにしており、URIには入力された値をつなげている。QAXIS10CCはCPPLE (ILE C++) で作られているので、変数値は忘れずにヌル終端 (x’00’で終わる)にしておく。そのあと、指定したURIを入力パラメータとしてAPI axiscTransportCreateでトランスポート・ハンドルを生成する。
【図表20】mainプロシージャー(1)
図表21ではトランスポート・ハンドルを生成後、属性値としてHTTPメソッドをAPI axiscTransportSetPropertyで指定している。今回は、指定した顧客コードの情報照会を想定しているので、HTTPメソッドはGETになる。
【図表21】mainプロシージャー(2)
GETで情報を取得し、REST webサービス側にデータを送信しないため、今回はAPI axiscTransportSendは使用せず、属性の指定後は API axiscTransportFlushを用いてHTTPリクエストを送信している。リクエストの送信後は API axiscTransportReceiveを使用してレスポンスを受け取る。受け取るデータが存在する限り、ループして受け取るロジックである。
図表22ではデータを受け取ったあと、画面に表示している。今回は図表23のように、画面表示にはdisplayMessageプロシージャーを別途作成している。データ表示が完了すると、不要になったトランスポート・ハンドルを破棄して処理が終了する。
【図表22】mainプロシージャー(3)
【図表23】DisplayMessageプロシージャー
またTransport API使用時のエラーや、HTTPステータス・コードをハンドリングするプロシージャーとして、図表24のようにcheckErrorプロシージャーを使用している。トランスポート・エラー・コード、またコードに関するメッセージを取得するAPIとして、それぞれ axiscTransportGetLastErrorCodeとaxiscTransportGetLastErrorが用意されており、HTTPステータス・コードの取得はaxiscTransportGetPropertyで属性から読み取る。
【図表24】checkErrorプロシージャー
ここまで見てきたソースで実装されているIMAGPGM/CUSTINFCLを実行した際の5250画面での表示例が、図表25となる。REST webサービス経由でJSON形式のデータを取得でき、データがない場合もHTTPステータス・コード404を取得できていることがわかる。
【図表25】IMAGPGM/CUSTINFCL実行イメージ
このようにTransport APIを用いることで、ILE RPGからREST webサービスを簡単に呼び出せる。IBM iをアプリケーションの中心に位置付け、外部の各REST webサービスを呼び出すようにすれば、シンプルなアプリケーションの作成が可能になる。
●
以上、ILE RPGを外部に向けてREST webサービスとして展開する方法と、外部のREST webサービスをIBM iのプログラムで直接活用する方法を解説してきた。いずれもシンプルで、わかりやすい実装形態である。本稿を参考にしながら、ぜひ挑戦してほしい。
・・・・・・・・
著者プロフィール
中村陽一 氏
2003年、日本アイ・ビー・エム システムズ・エンジニアリング入社。2004年よりIBM iを主たる技術エリアとして活動。2010年に日本IBMへ出向、提案局面における技術支援を担当。2013年にISEへ帰任後は、主としてプロジェクト実施局面における技術支援を担当、現在に至る。
・・・・・・・・
i Magazine 2017 Winter(11月)掲載