すべてのCLPのテンプレートとなるサンプル・ソースを公開する。
弊社で製品のCLPを開発するときのベースになるのが
ここで紹介するCLPのテンプレートである。
多くの試行錯誤やテストを経てこの姿にたどり着いた。
このCLPは製品の一部として様々な場面で使用されることを前提に
考えられている。
社内のCLP開発のベースとして利用して頂ければと
ここに公開する。
[AA1_SAMPLE: テンプレート・サンプル CLP]
ソースはこちらから
0001.00 PGM 0002.00 /*-------------------------------------------------------------------*/ 0003.00 /* AA1_SAMPLE : テンプレート・サンプル CLP */ 0004.00 /* */ 0005.00 /* 2018/02/01 作成 */ 0006.00 /*-------------------------------------------------------------------*/ 0007.00 DCL VAR(&MSG) TYPE(*CHAR) LEN(132) 0008.00 DCL VAR(&MSGID) TYPE(*CHAR) LEN(7) 0009.00 DCL VAR(&MSGF) TYPE(*CHAR) LEN(10) 0010.00 DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10) 0011.00 DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(132) 0012.00 DCL VAR(&TYPE) TYPE(*CHAR) LEN(1) 0013.00 DCL VAR(&TOPGMQ) TYPE(*CHAR) LEN(10) 0014.00 DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) + 0015.00 VALUE('*ESCAPE ') 0016.00 DCL VAR(&APIERR) TYPE(*CHAR) LEN(116) + 0017.00 VALUE(X'000074') /* 2 進数 */ 0018.00 DCL VAR(&NULL4) TYPE(*CHAR) LEN(4) + 0019.00 VALUE(X'00000000') 0020.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR)) 0021.00 0022.00 /*( 環境の取得 )*/ 0023.00 RTVJOBA TYPE(&TYPE) 0024.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ */ 0025.00 CHGVAR VAR(&TOPGMQ) VALUE('*SYSOPR ') 0026.00 ENDDO /* バッチ */ 0027.00 ELSE CMD(DO) /* 対話式 */ 0028.00 CHGVAR VAR(&TOPGMQ) VALUE('*TOPGMQ ') 0029.00 ENDDO /* 対話式 */ 0030.00 0031.00 IF COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO) 0032.00 SNDPGMMSG + 0033.00 MSG('API: QUHDSPH の実行で次のエラーが発生 + 0034.00 しました。 ') MSGTYPE(*DIAG) 0035.00 GOTO APIERR 0036.00 ENDDO 0037.00 RETURN 0038.00 0039.00 APIERR: 0040.00 CHGVAR VAR(&MSGID) VALUE(%SST(&APIERR 9 7)) 0041.00 CHGVAR VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100)) 0042.00 CHGVAR VAR(&MSGF) VALUE('QCPFMSG ') 0043.00 CHGVAR VAR(&MSGFLIB) VALUE('QSYS ') 0044.00 GOTO SNDMSG 0045.00 0046.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) + 0047.00 MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) + 0048.00 MSGFLIB(&MSGFLIB) 0049.00 SNDMSG: IF COND(&MSGID *EQ ' ') THEN(DO) 0050.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) + 0051.00 TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE) 0052.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0053.00 ENDDO 0054.00 ELSE CMD(DO) 0055.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0056.00 MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) + 0057.00 MSGTYPE(&MSGTYPE) 0058.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0059.00 ENDDO 0060.00 ENDPGM
[解説]
まずCLPの名前が AA1_SAMPLE というのはSTRSEU やPDMで見たときに一番先頭に位置することを
目的としている。
0016.00 DCL VAR(&APIERR) TYPE(*CHAR) LEN(116) + 0017.00 VALUE(X'000074') /* 2 進数 */
は APIを呼び出すときのエラー・コードとしてAPIに渡して
APIの呼び出しの直後に
0031.00 IF COND(%SST(&APIERR 5 4) *NE &NULL4) THEN(DO) 0032.00 SNDPGMMSG + 0033.00 MSG('API: QUHDSPH の実行で次のエラーが発生 + 0034.00 しました。 ') MSGTYPE(*DIAG) 0035.00 GOTO APIERR 0036.00 ENDDO
を入れて欲しい。
APIでの実行エラーがあれば
0039.00 APIERR: 0040.00 CHGVAR VAR(&MSGID) VALUE(%SST(&APIERR 9 7)) 0041.00 CHGVAR VAR(&MSGDTA) VALUE(%SST(&APIERR 17 100)) 0042.00 CHGVAR VAR(&MSGF) VALUE('QCPFMSG ') 0043.00 CHGVAR VAR(&MSGFLIB) VALUE('QSYS ') 0044.00 GOTO SNDMSG
によってAPIのエラー・メッセージが取得できるようになっている。
また実行の最初には必ず
0022.00 /*( 環境の取得 )*/ 0023.00 RTVJOBA TYPE(&TYPE) 0024.00 IF COND(&TYPE *EQ '0') THEN(DO) /* バッチ */ 0025.00 CHGVAR VAR(&TOPGMQ) VALUE('*SYSOPR ') 0026.00 ENDDO /* バッチ */ 0027.00 ELSE CMD(DO) /* 対話式 */ 0028.00 CHGVAR VAR(&TOPGMQ) VALUE('*TOPGMQ ') 0029.00 ENDDO /* 対話式 */
を行ってこのCLPで対話式環境で実行されたのかバッチ処理として実行されたのかを
調べている。
というのは後でエラーになったときは対話式環境でエラーになった場合は
このジョブに *DIAG または *ESCAPE のメッセージを出力するが
バッチ式で実行された場合は QSYSOPRにメッセージを出力するようにしている。
大事なことはエラーが発生したときに必ずエラー・メッセージが報告されることである。
CLPの処理の一番最初に
0020.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
としているのは何か不明なメッセージが発生したときはすべて GOTO ERROR で
ERROR という名前のタグにジャンプするように指示している。
0046.00 ERROR: RCVMSG MSGTYPE(*LAST) RMV(*NO) MSG(&MSG) + 0047.00 MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) + 0048.00 MSGFLIB(&MSGFLIB)
ではRCVMSG によってエラー情報を取得してエラーのMSGFなども取得している。
0049.00 SNDMSG: IF COND(&MSGID *EQ ' ') THEN(DO) 0050.00 SNDPGMMSG MSGID(CPF9897) MSGF(QCPFMSG) MSGDTA(&MSG) + 0051.00 TOMSGQ(&TOPGMQ) MSGTYPE(&MSGTYPE) 0052.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0053.00 ENDDO 0054.00 ELSE CMD(DO) 0055.00 SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) + 0056.00 MSGDTA(&MSGDTA) TOMSGQ(&TOPGMQ) + 0057.00 MSGTYPE(&MSGTYPE) 0058.00 MONMSG MSGID(CPF2400) EXEC(RETURN) 0059.00 ENDDO
ではMSGIDがあるときはMSGFなどを使ってメッセージを送出するが
CLPの文中で
CHGVAR VAR(&MSG) + VALUE(' この処理には *IOSYSCFG 権限が必要で + す。 ') GOTO SNDMSG
のような処理をした場合でもメッセージはCPF9897によって出力されるように
なっている。
エラー・メッセージのタイプは最初は
0014.00 DCL VAR(&MSGTYPE) TYPE(*CHAR) LEN(10) + 0015.00 VALUE('*ESCAPE ')
は *ESCAPEとして初期値が定められているがCLPの文中で
CHGVAR VAR(&MSGTYPE) VALUE('*DIAG ')
として変更すればメッセージは *ESCAPEではなく *DIAG として送出される。
メッセージが *ESCAPEで戻されるとこのCLPの実行結果は上位のプログラムでは
エラーが発生したものと解釈されるが *DIAG (診断メッセージ)であれば
上位のプログラムまでエラーとなることはない。
このようにこのテンプレートCLPは実用的にかなり奥深いところまで
考慮されている。
なお開発中にエラーが発生したときは
0020.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
を一時的にコメント化しておくとエラーでアベンドするのでエラー箇所を
特定することができる。
リリースするときは
0020.00 MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
をもう一度生かしておくこと。
エラーの発生でアベンドしたのではエンド・ユーザーに不信感を与えてしまうので
弊社製品はそこまでも考慮してすべてのエラーはモニターできるように
組み上げてある。