前回に引き続きIBM i上でのウェブサービス構築に関する記事をお送りします。今回はIBM iの統合ウェブサービス(IWS)を利用したRPGによるウェブサービスの構築方法についての基礎を解説します。IWSを使うことで、既存のRPGプログラムを容易にウェブサービスに仕立て直せる上に、RPGからもそれを呼び出せるという点は、IBM iユーザーにとって大きなメリットと言えるでしょう(編集部)
安全で信頼できるWindowsおよび他のシステム向けのデータアクセスを提供することで、ウェブサービスはRPGプログラムに新たな命を吹き込みます。
02/17/2016 ジョン・パリス&スーザン・ガントナー
遡ること2012年に、私達は「RESTが必要?」という記事を公開し、そこでRPGによる簡単なREST**ウェブサービス開発の基礎について書きました。(iWorldで掲載した記事はこちら)そのとき、このタスクのためにIBMの統合ウェブサービス(IWS)が使えたかも知れなかったのですが、当時IWSはSOAPウェブサービスしか生成せず、私達が実装しようとしている種類の単純なサービスには過剰なものでした。
年月の経過とともに事態は変わり、IBMのティム・ロー氏が何度も指摘したように、その間にIWSは著しく更新され続けてきました。IWSは今や追加機能としてRESTウェブサービスに止まらず、素のテキストからXML、JSONに至るまで、多くの異なる形式での要求と応答を可能にします。
RPGサブプロシージャ
サービスの設定を行うためのIWSウィザードの詳細な使い方を議論する前に、使用されるRPGプログラムについて何点か強調する必要があります。これらの要点の幾つかは単に「あなたは知らないかも知れない」類のものですが、とりわけ1つのテクニックは、既存のルーチンをウェブサービスとして使用する場合には明確に理解することが重要です。
本稿で示されているソースプログラムは、顧客番号(CustNumber)が渡されるとその顧客の名前と住所という基本的な情報を検索する単純なサブプロシージャを表しています。そのような顧客が存在しない場合は、名前に「*** Not found ***」がセットされます。
(A)で始まる部分で、CustInfoという応答文を構築するのに使用されるデータ構造を定義しました。CustMastというファイルからデータを読み込むのに必要なフィールド名を単にリストしていることに注意してください。フィールドの長さまたは他の定義は不要で、コンパイラはファイル定義からそれらを取得します。このようにコーディングすることのその他の利点は、CHAIN命令が成功すると応答用データ構造の全フィールドが自動的に満たされることです。コピーは不要です。このテクニックに不慣れでもっと知りたいのであれば、その詳細情報について私達の「D-spec Discoveries」という記事を読むことをお勧めします。
(B)を強調していますが、その理由はこれを加えることで、ウェブサービス内と同様にこのルーチンを通常のRPGでも使えるようになるからです。この「魔法のソース」はRTNPARMキーワードです。これがどのように役に立つかを最もうまく説明するために、通常のRPGプログラムの中からこのルーチンを呼び出す方法を見てみましょう。そのコードは一般的に以下の様になるでしょう。
CustInfoData = GetCustInfo( custNum ); |
問題は、ウェブサービス・ウィザードが返戻値として4バイト整数の使用だけを許しているということです。私達は4バイトよりずっと多い複数フィールドから成るデータ構造をもっています!詳細には立ち入りませんが、これは下層のJavaツールによって課される制約です。RTNPARMキーワードという魔法は、返戻値を受け取って、代わりにそれを(最初の)パラメータに変換することです。RPGはこの機能を大きな返戻値のパフォーマンス向上策として導入しました。しかし、この機能はそのようなルーチンをウェブサービス・ウィザードによって使用できるようにするという喜ばしい副作用ももっています。これによって、今やこのルーチンは2つのパラメータをもち、返戻値は無いように見えます。そしてそれは、通常のRPGプログラムの中で普通私達が行うやり方でそのルーチンを使用する機能に影響を与えることなくこれを行います。これは予期しない素晴らしい利点です!更なる詳細については「Big Changes for RPG in IBM i 7.1」をお読みください。
このテクニックは、ウェブサービスとして再度利用されるサブプロシージャに適用できるだけでなく、Javaおよび他の機能から同じ基本的制約の下でこれらのサブプロシージャを使う簡単な方法としても適用できます。このことは明白な選択肢ではないので、この情報をIWS文書に追加して欲しいと思います。
h NoMain Option(*SrcSTmt : *NoDebugIO) fCustMast IF E K DISK (A) d CustInfo ds Inz d Cust# d Name d Addr d City d State d Zip (B) p GetCustInfo b Export d PI LikeDS(CustInfo) d RTNPARM d CustNumber 5s 0 d CustNotFound c '*** Not found ***' (C) Chain ( CustNumber ) CustMast; If Not %Found(CustMast); (D) Reset CustInfo; // Clear out all data Cust# = CustNumber; // Set customer number requested Name = CustNotFound; // and error code EndIf; Return CustInfo; p GetCustInfo e |
(C)は単純に顧客データを取得するCHAIN命令です。これをここで強調した理由は、最近偶然見つけたちょっとしたヒントに言及できるからです。キーフィールドが括弧の中に入っていることに気付きましたか?こうすることで、キーのデータ型、サイズ等々がファイルと一致していることを保証する必要がなくなります。コンパイラがあらゆる違いの面倒を見てくれます。理由はうまく説明できませんが、キーを目立たせることで命令文の可読性も向上するようです。
(D)はCHAIN命令が成功したかどうかを検査します。成功していれば、要求されたすべてのデータはデータ構造に入れられ、結果を返す以外にすることはありません。しかし、顧客が見つからなければ、前回の操作の結果を消去(RESET)し、データ構造内の適切な場所に要求された顧客番号とエラーメッセージをセットする必要があります。
コードをコンパイルする際に、プログラム呼び出しマークアップ言語(PCML)を生成すると必ず指定してください。PGMINFOオプションパラメータを使ってPGMINFO(*YES *MODULE)と指定することで、モジュールオブジェクト中にこのデータを埋め込むことをお勧めします。PCMLはRPGプログラムと接続するのに必要な情報をIWSウィザードに提供します。
このコードがモジュールとしてコンパイルされたら、それをサービスプログラムに追加します。そして、それはウェブサービスが使用するあのサービスプログラムです。ここで、IWSはプログラムオブジェクトも使用できることは注目に値しますが、このケースでは既存のサブプロシージャの再利用を明示したかったのです。
ウェブサービスを設定する
IBMにはそのプロセスを説明している幾つかのウェブページがあるので、ここでは詳細に立ちることはしません。しかし、私達はこちらから視聴できるそのプロセスの簡単なビデオを作成しました。
以下に列挙したのは、役に立つと思った主要なIBMページです。
- Integrated Web Services for IBM i
これはIWSのすべてのことに関する基本的なホームページです。 - Integrated Web Services for IBM i
そう、同じページ表題です!この一連のページはウェブサービス・サーバを作成するプロセスから、プログラムをウェブサービスとして配置するプロセスまでを示してくれます。 - Integrated Web services for IBM i updates
このページは(2015年6月の)最新の更新の説明行い、必要なPTFレベルを特定しています。また、結果中のネストされた配列のような、新しくサポートされるようになった機能の例も提供しています。 - “Building a REST service with integrated web services server for IBM i” Part 1とPart 2。最後に挙げましたが、一番重要性が低いということではありません。これらのページはステップを踏んでRESTウェブサービスの設定プロセスを示してくれます。
ウェブサービスをテストする
SOAPウェブサービスの実装と違い、IBMはRESTウェブサービス用の組み込まれたテスト機能を提供していません。正直その決断に私達は喜んでいます。というのも、SOAPテスターが使い難く、まったく直観的でないと私達は常に感じていたからです。ウェブサービスをテストするのに、私達はいつも無料のSOAPUIツールを使っています。幸いなことに、このツールはSOAPウェブサービスのサポートに加え、RESTウェブサービスのテストを可能にする更新がなされています。
しかし、RESTウェブサービスをテストするもっと簡単な方法があります。単純にブラウザーを使うことができます!ほとんどのRESTサービスは(IWSで作成されたものを含め)ウェブブラウザーで使用されるHTTPプロトコルが使えます。ですから、望みの要求(IWSウィザードがメッセージの基本形式を示しています)を単純にURLに入力することができ、応答がブラウザーに表示されます。私達の新しいサービスのテストでは、応答をXML形式で返すように選択しました。なぜなら、RPGプログラムからサービスを使用しているとすると、結果をXML-INTO命令を使って処理するのは容易だからです。また図1から分かるように、結果を見るのが容易にもなります。結果を含んでいるXML要素が_TRNPARMという名前(あなたにはお馴染みの名前の筈です)であることに注意してください。その要素の中に戻されたデータ構造のフィールドがあります。サブプロシージャが正規のパラメータの中にその値を返していたならば、その要素名はパラメータの名前になっていたでしょう。
図1
この例では、使用するウェブサービス(custinfo)と顧客番号(00345)が両方とも基本URL中に指定されています。また、顧客番号が照会文字列の一部として渡されるように設定することも可能で、その場合にはURLは下記の様になったでしょう。
http://ideveloper:10021/web/services/custinfo/?custnumber=00345
どちらを使いますか?あなた自身の判断に任せます。私達の見解では、URL内で常に要求される情報(顧客番号)を含めるのは理に適っていますが、例えばもし顧客情報を更新できるようにウェブサービスを拡張したいなら、個々のフィールドを識別するために照会文字列の中のパラメータを使用するでしょう。
良い点、悩ましい点、そして・・・
これらの新機能の精査にはまだ長い道のりがあり、すべてがどのように繋がっているか理解が深まったら折り返し報告するつもりです。しかし、幾つかの共有すべき考えが間違いなくあります。これらの課題の幾つかは既に言及されている可能性がありますが、何も見つけられませんでした。
良い点
- サービスのパフォーマンスは極めて優れており、予想したよりも遥かに高速です。高負荷の下でそれがどの様に起こっているのかに言及する立場にはありませんが、私達が読んだ報告書はそれがうまく機能していることを示唆しています。プログラミングの観点からは、以前私達が概説した方法よりもサービスを作成する方が確かに容易です。要求を実際に処理し、それを送ることに気を配る必要がなく、単にパラメータを受け入れて結果を返すコードを書くだけです。
- パラメータをマッピングする等のためにウィザードの中で提供される機能は、明快で分かりやすいものです。
悩ましい点
これは長いリストに見えることになりそうです。全体としてこの一連のツールは素晴らしいものですので、このことはどうかすると不公平に見えますが、それは確かに遥かに優れている可能性があります。
- 最大の単一争点は文書化です。私達の理解では、IWSの目的の1つはウェブサービスについて何も知らない人達がそれを作れるようにすることです。問題は、文書で使用されているテクノロジーの大部分がUNIX風の方言の中の更に一方言であり、ウェブサービスについて何かを既に九分通り理解していることを要求していることです。
例えば、先に参照したステップ順のガイドでは、ステップ10で「ウェブサービスの実装コードにクライアント要求に関連したどの伝送情報を渡すかを指定します」とあります。はぁ?私達はRPGやPHPによる基本的なウェブプログラミングに馴染んでいるので、専門用語がまったくの異星語であるとまでは言いませんが、IWSが対象とする聴衆の中の多くのRPGプログラマーがこれを障壁と感じてもおかしくはありません。
確かに、これをIWSのせいにするのは多分不公平でしょう。これは、IBMが最近OSに追加している多くの機能に見られる現在進行中の問題です。もしIBMが、本当にこれらの機能が広く使われて欲しいと思うのなら、これは真に言及される必要のある問題です。これは量の問題ではなく、むしろ対象とする聴衆が共感できる言葉で製品説明ができない書き手の能力不足の問題です。 - ウィザードでは、特定フィールドの内容を(例えば)数値に限定するために正規表現を使うことができます。しかし、入力データがこの規則を破ってもエラーメッセージが出されません。単に出力がなされないだけです。このせいで正規表現を使った妥当性検査は少々無意味になります。RPGプログラムの中で妥当性検査を強制する方がましです。そうすれば、少なくともエラーの応答を返すことができます。
- 数値の話題に関して、このツールは何らかの理由で先行ゼロを消去して数値を返すようです。これは上記の例題で見られます。このツールは、実際のフィールド長を知っているので、このようにする理由がまったく理解できません。
-
ウィザードが生成するURLは大文字と小文字の区別をします。その結果、
…/web/services/custinfo/…の代りに
…/web/services/Custinfo/…
と入力すると、見つかりませんという醜いエラーが返されます。IBM i上で正規のウェブページを構築する場合、大半のウェブサイトとは違いURLは大文字と小文字の区別をしません。多分これはサーバ構成のどこかで微調整可能ですが、それについての参考情報を見つけることはできませんでした。
他にもいくつか特異的な点を挙げることはできますが、素晴らしいツールを試す気を失わせたいとは本当のところ思っていません。しかし、これらの事を知っておく必要はあると考えています。さもないと、私達と同様に真っ黒な画面を見つめて、サービスの構成を間違えたのだろうかと訝しく思いながら長時間を無駄にしてしまうでしょう。
悪い点
「悪い」というラベル付けをするに値すると私達が本当に感じたものはただ1つで、それはウィザードを使ってサービスの定義を編集する方法がないという事実です。
パラメータを変更する、あるいはXMLだけのサポートからJSONサポートを追加する必要がある場合、それを行う唯一の方法は既存のサービスを削除してサービスを再作成することです。もし多くのパラメータや他の設定が関わっていたなら、これは単に面倒と言うよりもエラーを誘発するものです。
まとめ
面倒な事に遭遇したものの、最新版のIWSができることに大変感銘を受け、これを試してみることを強くお奨めします。ウェブサービスはODBC/JDBCよりもWindowsや他のシステムに安全で信頼性の高いデータアクセスを提供するずっと優れた方法であり、RPGプログラムに新たな生命を与えます。
IWSで出来ることをもっと調査したら、もっと多くの記事を書くつもりです。その間に、コメント欄に経験談を寄せていただければと思います。IWSを利用していますか?ウェブサービスを提供する別の方法を調査していますか?もしそうなら、何がお気に入りのアプローチでしょうか?
**ご存知ない方のために。RESTはRepresentational State Transferの略です。ほら、今やあなたはずっと物知りになったでしょう!もっと良い定義が知りたければ、先に述べた記事を読んでください。