PythonからRPGプログラムを呼び出す、パート1
以前の記事で、Pythonスクリプトにパラメーターを渡して、RPGプログラムからそのスクリプトを実行する方法について紹介しました。記事に寄せられたコメントと私自身の好奇心から、RPGプログラムにパラメーターを渡して、PythonからRPGプログラムを呼び出すにはどのようにしたらよいか興味がわきました。少し調べてみたところ、itoolkitというPythonインターフェースを見つけました。
itoolkitは、 XMLSERVICE ツールキットとのインターフェースとしてIBMによって提供されるオープンソース プロジェクトであり、RPGプログラム、サービス プログラム、CLプログラム、およびPASEシェル コマンドを呼び出すことができます。itoolkitは、SSH端末を使用して、次のコマンドでインストールすることができます。
pip3 install itoolkit
私は、SSHクライアントとしてPuTTYを使用します(PuTTYのインストール方法については、 こちらの記事 を参照してください)。PCにPuTTYをインストールしたら、ACS(Access Client Solutions)から簡単にアクセスできるようになります。ACSは、PCにインストールされているSSHクライアントを自動的に検出して、そのクライアントにアクセスするためのリンクを提供します(図1)。
SSH端末を起動するには、IBM iでSSHデーモンを実行している必要があることに注意してください。SSHデーモンを開始するには、IBM iで次のCLコマンドを実行します。
STRTCPSVR *SSHD
SSH端末を起動すると、パスワードを入力するように求められます。有効なパスワードを入力したら、itoolkitをインストールするコマンドを実行できます(図2)。
itoolkitがインストールされたら、PythonがRPGと対話できるようになります。それでは、PythonからRPGへ、およびRPGからPythonへ文字列を渡す方法を示すシンプルな例を見てみましょう。
以下のコードでは、RPGプログラムを呼び出すことを可能にするitoolkitモジュールをインポートします。また、より連携しやすくなるように、それらのモジュールをローカル名に割り当てます。
from itoolkit import *
from itoolkit.lib.ilibcall import *
モジュールの準備ができたら、モジュールが提供する関数を使用できるようになります。RPGプログラムを呼び出すので、オブジェクトがあるライブラリーが、ライブラリー リストにあることを確認する必要があります。その処理を行うために、itoolkitモジュールに、CLコマンドを実行できるようにするコマンド(icmd )を追加します。ここでは、私のプログラムのオブジェクト ライブラリーが、確実にライブラリー リストにあるようにするために、 ADDLIBLE コマンドを追加しました。
itool.add(iCmd('addlible', 'addlible mllib'))
次に、私のプログラム Mlr100Tk の呼び出しを追加して、入力および出力パラメーターの両方を渡します。
itool.add(
iPgm('my_results',' Mlr100Tk')
.addParm(iData('InFirstName','10a','Mike'))
.addParm(iData('OutLastName','10a',' '))
)
itool.add 関数の中にある、3行のコードについて説明します。1行目の iPgmには、2つのパラメーターがあります。1つ目のパラメーターは、結果がどこに格納されるかを指示し、2つ目のパラメーターは、呼び出されるRPGプログラムの名前を指示します。次の2行は、RPGプログラムが予期しているパラメーターを定義し、 iDataによって定義されます。これはごく基本的な例であるため、RPGプログラムにファースト ネームを渡して、ラスト ネームが返されるだけです。これらのパラメーターは、両方ともアルファ データ タイプの10桁として定義しています。
最後に、 iLibCall 関数を使用して( itransport 変数を介して)、ライブラリー リスト エントリーを追加し、RPGプログラムを呼び出すコマンドを実行します。
itool.call(itransport)
このプログラムを呼び出すと、結果はJSON形式のディクショナリーとして返されます。それらの結果をさらに利用できるように変数に割り当てます。
# results are returned as a dictionary formatted as Json
mypgm_results = itool.dict_out('my_results')
Pythonスクリプトを実行する前に、呼び出されるRPGプログラムを示しておこうと思います。プログラムにはあまり多くの処理はないため、プログラム全体を一気に示します。
// Prototypes (entry parameters)
dcl-pr Mlr100Tk ExtPgm;
inFirstName char(10);
outLastName char(10);
End-pr;
// - - - - - - -
// Main procedure interface
dcl-pi Mlr100Tk;
inFirstName char(10);
outLastName char(10);
end-pi;
//---------------------
If %trim(inFirstName) = 'Mike';
outLastName = 'Larsen';
Else;
outLastName = 'Smith';
Endif;
*Inlr = *On;
Return;
私の方で行うのは、パラメーターをセット アップし、Pythonスクリプトへ返される出力パラメーターにデータを設定することだけです。
スクリプトとプログラムの用意ができたら、SSH端末を開いて、Pythonスクリプトを実行します(図3)。
スクリプトを実行して結果を出力すると(下のコード)、入力および出力パラメーターが格納されているJSONオブジェクトと、プログラムが正常に呼び出されたことを示す戻りメッセージを受け取ります。次いで、 Successという文字列がないか出力を調べます。その文字列があった場合は、端末に「 Success 」という単語を出力し、なかった場合は、エラーが発生したことを表示します。
print(mypgm_results)
if 'success' in mypgm_results:
print('Success!')
else:
print('Errors occurred.')
この例では、返される出力は小さいため、結果を簡単に読み取ることができます。しかし、返されるJSONがもっと大きく複雑な場合はどうなるでしょうか。スクリプトにコードを少し追加して、解読しやすいようにJSONを個々のコンポーネントに解析します。
# parse the Json response from the dictionary
print('\n')
print("Parameter passed TO Rpg: ", mypgm_results['InFirstName'])
print("Parameter passed FROM Rpg: ", mypgm_results['OutLastName'])
print("Status of the program call: ", mypgm_results['success'])
図4に、解析された応答を示します。
以上、簡単な紹介でしたが、PythonとRPGの統合のみならず、レガシー システムとの統合のための手引きとなれば幸いです。今後の記事では、さらに一歩進んで、データ構造をRPGに渡す方法について説明する予定です。