RPG

59. ILE-RPG の *SRVPGM の作成と ILEの奥義!

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 を作って公開すれば
直ちに新しいプログラムからもその関数が利用可能になるのである。
これは元のプログラムにほとんど手を加えずにオブジェクト・レベルでの再利用性という観点では
すばらしいことである。