CL

122. テンプレート・サンプル CLP: AA1_SAMPLE

すべての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))

 

をもう一度生かしておくこと。
エラーの発生でアベンドしたのではエンド・ユーザーに不信感を与えてしまうので
弊社製品はそこまでも考慮してすべてのエラーはモニターできるように
組み上げてある。