Rational Open Access RPG Editionのワークショップ パート1
グリーン・スクリーンを越えた思考による価値の付加に集中する
Rational Open Access: RPG Edition (RPG OA) は RPG の新機能の1つで、更新作業に便利です。RPG OA により、RPG の入出力操作を、標準の IBM i 入出力ルーチンから、あなたが開発する「ハンドラー」コードにリダイレクトできます。
一目見て簡単に理解できる RPG プログラムから始めてみましょう。プログラム IFS01 中のコード (図1) は、ディスク・ファイルを読み取り、各レコードをプリンターに印刷します。このプログラムに「仕掛け」はありません。ファイルは USROPN キーワードで定義しました。これは、明示的に開いていることを意味します。ファイルを開いたら、「エンドレス・ループ」が、end of file まで、または error 状態が発生するまでそのファイルを読み取ります。図2 は、プログラム出力を示しています (IBM が提供した実例ファイル QIWS/QCUSTCDT を使用しています)。
この記事では、実例プログラム IFS01 を使用して、どのように RPG OA ハンドラー・プログラムを開発し、IFS のテキスト・ファイルからデータを読み取るか説明していきます。実例プログラムへの変更は最小限に抑えてあります。ハンドラー・プログラムで使用すると、実例プログラムで使用している RPG ファイルの命令コードで実行される OPEN、READ、CLOSE の各関数、また %eof および %error 組み込み関数がハンドラー・プログラムに任されます。
プロセスを簡単にたどることができるよう、一度に1ステップずつハンドラー・プログラムを構築します。実例プログラムとハンドラーに対するその都度加えられた変更について説明します。プログラムとハンドラーの関係を完全に理解するために必要なRPG OA の機能を挙げていきます。
始める前に、実例プログラム IFS01 をダウンロードし、コンパイルして実行します。ハンドラーを開発する前に作業プログラムを手に入れる必要があります。
RPG Open Access の前提条件
IBM は当初、RPG OA を、 IBM i 6.1 および 7.1 の無償の Licensed Program Product (LPP) としてリリースしました。IBM は 2012年1月に、IBM i 6.1 または 7.1 向け ILE コンパイラーを使用するライセンス付与されたすべての IBM i 顧客は無償でその製品を入手できると発表しました。
HANDLER キーワードをプログラムに追加する
必須ソフトウェアをシステムに準備したら、HANDLER キーワードを実例プログラムに追加できます。図3 は、コード例プログラム IFS02 を示しています。これには、キーワードがコールアウト A で追加されています。この形式の HANDLER キーワードは、何らかのファイル入出力操作があったときに、プログラム OARPG/IFSHDLR1 を呼び出します。この例では、ライブラリー OARPG を使用していますが、システムのどのライブラリーを使用してもかまいません。
IFS02 プログラムをコンパイルして、実行すると、図4 のようなエラー・メッセージが表示されます。結果生じる MCH3401 エラーはわかりにくいことはありません。存在しないプログラム (ハンドラー・プログラム OARPG/IFSHDLR1) を呼び出しているだけです。プログラムに CALL 命令があり、そこにないプログラムを呼び出そうとすると同じエラーになります。
しかし、IFS02 プログラムのどこで CALL が発生したのでしょうか。この時点では、元のプログラムにステートメントを1つ追加しただけです。HANDLER キーワードのステートメントです。ここで起きている内容を理解するためには、*INLR をオンにする最初の実行可能ステートメントにブレークポイントを設定する必要があります。そのステートメントに行き着いたら、次のステートメント、OPEN ステートメントに進みます。デバッガーで OPEN ステートメントを起動すると、そのステートメントでエラーが発生するのがわかります。
ここで発生した内容を見てみましょう。HANDLER キーワードを追加したとき、実行時に、ファイルのすべての入出力操作をキーワードで指定したプログラムにリダイレクトするよう、RPG コンパイラーに命令しました。OPEN 命令を起動すると、プログラム IFS02 はハンドラー・プログラムを呼び出そうとします。つまり、従来のデータベース管理ルーチンではなく、ハンドラー・プログラムを暗黙的に呼び出しているのです。IBM i OS に関する限り、存在しないプログラムを呼び出そうとして、MCH3401エラー・メッセージが表示されている、よくある例に過ぎません。
ハンドラーのバリエーション
図5 のペアになっているコールアウトは、HANDLER キーワードの4 種類のバリエーションを示しています。このキーワードを使用して、入出力操作が発生したときに何を呼び出すかを指定します。コールアウト A には図3 のハンドラーと似ているプログラム・ハンドラーがあります。名前の付いた固定情報 IFSHDLR_PGM は、呼び出すプログラムを定義します。
コールアウトB では、呼び出すプロシージャーの名前を指定する方法の例があります。コールアウトFでは、ハンドラーはサービス・プログラム OARPG/IFSPROCS のプロシージャー QCUSTHDLR を呼び出しています。
コールアウト C と G は、プロシージャーのプロトタイプを指定することで、呼び出し側プログラム内のハンドラーをコーディングする方法を示しています。この場合、同じモジュール (またはプログラムにバインドされている別のモジュール) 内で呼び出すプロシージャー (IFSHDLR_PROTO) を定義できます。プロシージャーのプロトタイプを定義する場合、ハンドラーに値を渡す場合に RPG OA が使用するパラメーターを組み込む必要があります。ハンドラーをプログラム呼び出し (コールアウト E) またはサービス・プログラムのプロシージャーの呼び出し (コールアウトF) として定義する場合、パラメーターは暗黙的です。
コールアウト D およびコールアウト H のコードは、プロシージャー・ポインターを使用して実行時に決定されたハンドラー・プロシージャーを定義します。プロシージャー・ポインターは、呼び出すプログラムを変数として定義する場合、呼び出すプログラムを決定する際に、プログラム呼び出しと同じ柔軟性を備えています。
最初のハンドラー
図3 に示す IFS02 プログラムは、図5 でコールアウトEが示している内容に似たハンドラー定義オプションを使用しています。呼び出されているハンドラー・プログラムは IFSHDLR1 (図6) で、ハンドラーを呼び出したときにプログラム IFS02 で使用されている命令コードを表示するだけです。
図6 のコールアウト A のコードは、IBM が定義した QRNOPENACC include ファイルをコピーします。このファイルは RPG OA で使用される定数およびデータ構造を定義しています。このシリーズの次号では、include ファイルの機能とセクションについて徹底的に説明します。今のところは、ハンドラー・プログラム内に定義を組み込む必要があることを理解してください。コールアウト A の次の部分では、include ファイル内で定義されているQrnOpenAccess_T テンプレート・データ構造に似た、QOA データ構造を定義しています。コールアウト B のコードは、rpgOperation データ構造サブフィールドに似た opcode というスタンドアロン・フィールドを定義しています。
プログラムのパラメーター・リストをコールアウト C に定義しました。この定義を IFS02 プログラムの暗黙的パラメーター・リストと比較してください (図3 のコールアウト A)。ハンドラー・プログラム IFSHDLR1 を呼び出すと、RPG OA ランタイムが QOA データ構造のサブフィールドにハンドラーが使用する値を入力します。IFSHDLR1 ハンドラー・プログラムの場合のように、入力された値の 1 つは rpgOperation サブフィールドで、どのファイル入出力操作が実行されたかを示します。
IFSHDLR1 プログラムのコードは、命令コードを表示するにすぎません。プログラム IFS02 では、OPEN、READ、CLOSE の 3 つの命令コード・ファイルを使用します。自分でハンドラーを開発する場合、3 つの命令だけに限定する必要はありません。RPG OA は、ディスク、プリンター、およびディスプレイ・ファイルについて使用できるすべての RPG ファイル入出力命令コードをサポートしています。この例では、IFS02 プログラムで 3 つの命令コードを使用しています。
最初の実行可能ステートメントは、QOA.rpgOperation サブフィールドの値をスタンドアロン opcode フィールドに割り当てます。どの命令コードが実行されたか判断するには、単に opcode フィールドの値を IBM が定義した QrnOperation_ 定数のいずれかと比較するだけです (定数はインクルード・ファイルで定義されています)。
ハンドラーを実行する
IFSHDLR1 プログラムのコードをダウンロードし、Create Bound RPG (CRTBNDRPG) コマンド (コード・バンドルは iProDeveloper.com/code からダウンロードできます) を使用してコンパイルします。ハンドラーをコンパイルしたら、IFS02 プログラムを実行できます。IFSHDLR1 ハンドラーでの IFS02 プログラムの動作を確認するには、デバッグ・モードに入り、IFS02 の OPEN ステートメントにブレークポイントを設定します。プログラムを起動し、そのステートメントに到達したら、操作を始めます。コントロールが IFSHDLR1 プログラムに渡るのがわかると思います。このプログラムで、着信命令 (OPEN 命令) がどのように処理されるか確認できます。命令コードをそれぞれ処理すると、命令コードの数値が入ったショート・メッセージが表示されます。その数値は RPG OA include ファイルの名前の付いた固定情報 (Open= 1、Read = 4、Close = 18) に割り当てられています。
IFS02 プログラムをデバッグ・モードで実行する、しないにかかわらず、図7 のような出力、別のエラーが表示されます。この場合、エラーは MCH1202 で 10 進データ・エラーです。そのエラーは、IFSHDLR1 ハンドラーが READ 命令コードの処理から戻る場合に発生します。
あまり期待できるようには見えないでしょう。最も単純なハンドラーでもエラーが発生するのですから。ここで何が起きているのか見てみましょう。IFS02 プログラムは、QCUSTCDT データベース・ファイルで定義されたレコード・フォーマットのデータを処理しようとします。そのレコード・フォーマットには、文字フィールドとゾーン・フィールドの組み合わせが含まれています。ハンドラーがないと、IFS02 プログラムは、従来の RPG データベース管理ルーチンを使用して、ファイルからデータを読み取り、フィールドに入力します。データベース・ファイル自体に無効な数値データが入っていないと仮定すると、(最初の実例プログラム IFS01 のように) プログラムは単純に動作します。
ファイルのハンドラーを定義する場合、実質的に RPG プログラムに「管理する」、データベース管理 (またはプリンター、またはディスプレイ・ファイル管理) ルーチンは使用しないことを告げていることになります。それに関する限り、RPG OA は QrnOpenAccess_T データ構造の値を設定します。この構造は、ハンドラー・プログラムに渡されます。
ハンドラーが OPEN 命令を処理する場合、IFS02 プログラムはハンドラーにステータス・コードまたはエラー・コードのみ返すよう要求します。10 進データ・エラーは OPEN 命令では発生しません。データはハンドラーから QCUSTCDT レコード・フォーマット・フィールドに移動しないためです。ハンドラーは、READ 命令がエンドレス・ループ内で呼び出されると、コントロールを受けます。プログラムおよびハンドラーを進んでいくと、ハンドラーが READ 命令が呼び出されたと判断し、メッセージを表示して、戻ることで READ を「処理した」ことがわかりました。そのため、エラーはハンドラーで発生しませんでしたが (コミッションのエラー)、ハンドラーが処理しなかったことの結果、ハンドラーからの戻り時にエラーが発生しました(省略のエラー)。
ハンドラーは何ができなかったのでしょうか。有効な値を QCUSTCDT 数値フィールドに設定できなかったのです。IFS02 RPG プログラムは、READ を呼び出すときに、有効な結果を受信するよう要求します。ハンドラーを呼び出しても、特に魔法は起きません。ハンドラーは、レコード・フォーマットのすべてのフィールドについて有効なデータを返す、BIF 値 (end of file または error) を返す、あるいはステータス・コードを設定して命令が正常に完了できなかったことを示す必要があります。値、BIF、またはステータスを設定せずに READ 命令から単に戻ろうとするのは、完全な責任の放棄で、OS は MCH1202 エラーをコールアウトします。
プログラムを前に進めるには、MCH1202 メッセージに応答する必要があります (唯一妥当な応答は C のキャンセルです)。IFS02 プログラムをキャンセルしたら、CLOSE 命令コードも処理されることがわかります。奇妙なことに、プログラム IFS02 中の CLOSE 命令は、プログラムが READ 命令の直後にキャンセルされるために呼び出されません。ただし、暗黙的な CLOSE が提供され、ハンドラーにより処理されます。
次回、データを処理する
エラー状態に対する明確なソリューションは、READ 命令を呼び出したときに、ハンドラーから呼び出し元に対して有効なデータを提供することです。このシリーズの次号でその方法をお話しします。その間、フォローアップのため、実例プログラムとハンドラーをダウンロードし、コンパイルして実行してください。IFS02 と IFSHDLR1 の両プログラムをコンパイルして実行し、RPG OA をお使いの IBM i システムに搭載できれば、完全なハンドラー・プログラムを開発できるようになるでしょう。