ILE(Integrated Language Enviroment) とは邦訳すれば「統合型開発環境」とでもいうのだろうか?
任意の開発言語によって開発された複数のサービス・プログラム(*SRVPGM)を
1つにまとめて(バインド)ひとつの *PGM とできることである。
例えばTCP/IP通信のAPIは C/400からしか使用できないが C/400でサービス・プログラムを作れば、
それをILE-RPGでBINDして使うことができる。
同じILE-RPGどうしであっても頻繁に使用する共通のビジネス・ロジックは *SRVPGM として
部品化しておけば ILEとして BINDして再利用が可能である。
つまり *SRVPGM とは DLL (Dynamic Linc Library) と考えるとわかりやすいというよりも
静的なDLL そのものである。
DLL を開発した経験のある人であれば *SRVPGM の構造は非常に良く似ていることに気づくであろう。
ここでは ILE-RPG のみによるILE の例を紹介しよう。
ILEソースは
CRTSRCPF FILE(MYSRCLIB/QRPGLESRC) RCDLEN(112) IGCDTA(*YES) AUT(*ALL)
のように 112バイトで作成しておく。
【 ILE-RPG サービス・プログラム】
ILE-RPG によって *SRVPGM を作成するときは ILE-RPGソースとEXPORT関数のソースの2つが必要になる。
【 *SRVPGMソース】
*SRVPGM ソースの構造は
- 関数のプロトタイプの定義(IMPORT とEXPORT)
- EXPORT関数の内容の定義
の2つの構造から成る。これも C/400などで使用する関数を最初に定義するのと同じである。
0001.00 **************************************************** 0002.00 * プロシージャーのプロトタイプ宣言 * 0003.00 **************************************************** 0004.00 D*( SETFLD のプロトタイプ宣言 ) 0005.00 D SETFLD PR 5A 0006.00 D FILED 20A Value 0007.00 D VALUE 256A Value 0008.00 /COPY QSYSINC/QRPGLESRC,QUSEC 0009.00 D TRUE C CONST('TRUE ') 0010.00 D FALSE C CONST('FALSE') 0011.00 0012.00 ************************************************************ 0013.00 * SETFLD : HTML テンプレートにフィールド値をセット * 0014.00 ************************************************************ 0015.00 *---( SETFLD PROCEDURE ここから )------------------------* 0016.00 *( 出力プロシージャーの定義 ) 0017.00 P SETFLD B EXPORT 0018.00 D SETFLD PI 5A 0019.00 D FIELD 20A Value 0020.00 D VALUE 256A Value 0021.00 D KEKKA S 9B 0 0022.00 C FIELD CAT X'00':0 FIELD 0023.00 C VALUE CAT X'00':0 VALUE 0024.00 C*----------------------------------------------------+ 0025.00 C CALLB 'RPGSETFLD' 99 0026.00 C PARM FIELD 0027.00 C PARM VALUE 0028.00 C PARM KEKKA 0029.00 C*----------------------------------------------------+ 0030.00 C KEKKA IFGE 0 0031.00 C RETURN TRUE 0032.00 C ELSE 0033.00 C RETURN FALSE 0034.00 C END 0035.00 P SETFLD E 0036.00 *---( SETFLD PROCEDURE ここまで )------------------------* 0037.00
まず最初の D仕様書で SETFLD という名前のEXPORT関数のプロトタイプを定義している。
プロトタイプとは戻り値 5A を定義(SETFLD PR 5A
)しているが、
戻り値の無い場合は 5A の記入は必要ない。
ここでは SETFLD を FIELD と VALUE という2つのパラメータを持つ関数として定義している。
次に C仕様書で SETFLD という関数の内容を定義するわけであるが
P SETFLD B EXPORT から P SETFLD E で囲まれたあいだに記述する。
つまり B (begin) から E(End) のあいだに記述するという意味である。
ここでももう一度
0018.00 D SETFLD PI 5A 0019.00 D FIELD 20A Value 0020.00 D VALUE 256A Value
によってプロトタイプと同じものを定義する。
必要な作業フィールドがあれば
0021.00 D KEKKA S 9B 0
と定義する。
後は任意に記述すればよいわけであるが、この例では C言語によって作成された
*SRVPGM をさらに呼び出している。
0022.00 C FIELD CAT X'00':0 FIELD 0023.00 C VALUE CAT X'00':0 VALUE
のように NULL値を付加しているのは C言語は NULL-STOPが必要であるからである。
【 EXPORTソース】
EXPORT 関数を定義するために QSRVSRC という名前のソース・ファイルを
CRTSRCPF FILE(MYSRCLIB/QSRVSRC) IGCDTA(*YES) AUT(*ALL)
のようにして作成しておく。
次の3行を追加する。
0001.00 STRPGMEXP PGMLVL(*CURRENT) 0002.00 EXPORT SYMBOL("SETFLD") 0003.00 ENDPGMEXP
QSRVSRC はあくまで EXPORT関数の名前 を定義するだけでよい。
【 *SRVPGMのコンパイル】
CRTRPGMOD MODULE(MYLIB/TESTMOD) SRCFILE(MYSRCLIB/QRPGLESRC) AUT(*ALL)
によって *MOD を作成してから、
CRTSRVPGM SRVPGM(MYLIB/TESTMOD) MODULE(MYLIB/TESTMOD) SRCFILE(MYSRCLIB/QSRVSRC) SRCMBR(*SRVPGM) ACTGRP(*CALLER) AUT(*ALL)
によって *SRVPGM を作成する。
ここで覚えておいて頂きたいのは *MOD は CRTRPGMOD によって生成されるが、
これは次の CRTSRVPGM のために必要なだけであって、*SRVPGM が作成されてしまえば
*SRVPGM の実行のためには *MOD は必要無い。
VisualC++ のビルドも .obj を生成するが最終的に必要なものは .exe や .dll などだけであるのと同じである。
この例では *MOD は同じライブラリーに作成しているが、実際には *MOD だけを一時的に保管する
ライブラリーを用意しておくほうが望ましい。
ライブラリーを配布するときには *MOD は必要無い。
このように *MOD 用のライブラリーを別のものにしておけば再配布のサイズを小さくすることができる。
もうひとつ重要な要素として「活動化グループ」(ACTGRP) がある。
この説明は別の項でくわしく説明する。
【 親ILE-RPGソース】
*SRVPGM を呼び出すILE-RPGの作成は簡単である。
0001.00 /COPY ASNET.USR/QRPGLESRC,PROTOTYPE 0002.00 D SETFLD PR 5A ExtProc('SETFLD') 0003.00 D FLD 20A Value 0004.00 D VALUE 256A Value 0005.00 C CALLP SETFLD('SHCODE ': VALUE) 0006.00 C EVAL RESULT = SETFLD('SHCODE': VALUE)
まず、
0002.00 D SETFLD PR 5A ExtProc('SETFLD') 0003.00 D FLD 20A Value 0004.00 D VALUE 256A Value
によって EXPORT関数のプロト・タイプを定義するが、これは多くの*PGMでの再利用を考えると
別のソースに登録しておいて、
0001.00 /COPY ASNET.USR/QRPGLESRC,PROTOTYPE
のようにしてインクルードするやり方が一般的である。
EXPORT関数の結果を無視してもよいのであれば
0005.00 C CALLP SETFLD('SHCODE ': VALUE)
で十分であるが、結果を使用したいのであれば
0006.00 C EVAL RESULT = SETFLD('SHCODE': VALUE)
のような記述となる。
CRTRPGMOD MODULE(MYLIB/TESTPGM) SRCFILE(MYSRCLIB/QRPGLESRC) AUT(*ALL)
によって *MOD を作成してから
CRTPGM PGM(MYLIB/MYPGM) MODULE(MYLIB/MYPGM) BNDSRVPGM(MYLIB/TESTMOD) ACTGRP(*NEW) AUT(*ALL)
のようにして *SRVPGM をバインドした *PGM を作成する。
【 ビジネス・ロジックの再利用 】
さてここからが重要な話となる。
これまでの *SRVPGM の作成の過程の中でもし気づいた方がいればかなり鋭いと言えるであろう。
EXPORT 関数の記述について注意深く眺めていけば通常の RPGでもEXPORT関数さえ定義してやれば、
*PGM にも *SRVPGM にも使えるということである。
つまり1つのソースで *PGM も *SRVPGM も生成できるのである。
これは単独でも動作する *PGM の必要な関数を *SRVPGM として他の *PGM に公開することが
できるという原理である。
この手法は EnterpriseServer にも利用されている。
WebScript や SQLScript を処理するための汎用的な CGI である「COMCGI」は
IBMオリジナルHTTPサーバーから呼び出されるときは単独の *PGM として動作して、
HTTPサーバー Alaska には *SRVPGM としてバインドされている。
1つのソースで2つの機能を提供していることになる。
さらにもう少し進めて考えてみよう。今、既存のかなり複雑な処理を行うRPGプログラムが存在していて
新しいプログラムから、その処理関数だけを利用したいとする。
元のプログラムの処理関数を EXPORT関数として定義して、*SRVPGM を作って公開すれば
直ちに新しいプログラムからもその関数が利用可能になるのである。
これは元のプログラムにほとんど手を加えずにオブジェクト・レベルでの再利用性という観点では
すばらしいことである。