ILE RPG:システムAPI・組み込みSQL活用術 ~IBM iアプリケーション開発 最新事情 Part Ⅱ

 

 

 

ILE RPGのさらなる活用に向けて 

 Part Iで触れているとおり、IBM iではEclipseをベースとしたRational Developer for iが開発環境として進化を続けている。同様に、プログラミング言語としてのILE RPGも、OSのリリースごとに機能拡張を続けている。

 一方、実際のシステム環境におけるRPGの使われ方に焦点を当てると、データベースに関しては外部ファイル記述を用いたレコード・レベル・アクセス(READ、CHAIN、WRITE命令)を実行し、CLコマンドで提供されるような機能はCLプログラムやQCMDEXC、QCAPCMDを適宜組み合わせて作成するケースが多いと思われる。

 RPG(OPM RPG、ILE RPGを含めて)では組み込みSQLという形でデータベースへSQLアクセスでき、またIBM iがOSとして提供しているシステムAPIを直接呼び出すことも可能である(Part Iにあるように、組み込みSQLに関してもソースの80桁制限の撤廃により、組み込みSQLを利用するプログラム・コードの可読性が一段と向上している)。

 そこでPartⅡでは、「ILE RPG:システムAPI・組み込みSQL活用術」と題して、ILE RPGからOS提供のシステムAPIを呼び出す方法や、さらなる組み込みSQLの活用法に関する情報をお届けしたい。

 

ILE RPGでのシステムAPI活用術

システムAPIとは

 IBM iでは豊富なシステムAPIとして、CLコマンドでは実現できない機能なども提供されている。どのような機能が提供されているかは、IBM i Knowledge Centerの一覧で確認できる。

 システムAPIとしては大きく、情報の取得(CLコマンドで言うとRTVxxxxxx系)を目的とするものと、何らかの機能の実行(ADDxxxxxxやCRTxxxxxxといったところ)を目的とするものに分けられるだろう。さらに情報取得系のシステムAPIは、図表1のように2つのタイプに大別できる。

 

1.リスト形式API 

 リスト形式APIとは、そのAPIで情報を取得するが、取得した情報はいったんオブジェクト・タイプが*USRSPCのユーザー・スペース・オブジェクトに格納され、ユーザーはそこから情報を取り出して利用する形式のものである。そのため、以下の順序で実行することになる。

 

●API QUSCRTUSを用いてユーザー・スペース・オブジェクトを作成

●情報を取得するAPI自体を実行

●API QUSRTVUSを用いてユーザー・スペース内のデータを取り出す

 

 代表的なものとしては、QUSLJOB(ジョブのリスト取得)が挙げられる。QUSLJOBはいわば、WRKACTJOBの詳細版である。ジョブ実行状況がMSGWになっているジョブの存在を監視する運用を考えた場合、最も簡便なのはWRKACTJOBのスプール出力をテーブルにコピーし、各レコードのジョブ状況の桁を読み取って判別するという方法であり、よく利用されている。

 スプール出力に関しては出力形式がOSリリースによって変更されることがあり、出力形式の変更に応じて監視プログラムの変更も必要となる。実際i5/OS V5R3からIBM i 5.4のタイミングで、WRKACTJOBのスプール出力の形式変更(現行ユーザー欄の追加)が加えられたため、このような対応をされた記憶がある方もおられるであろう。一方でQUSLJOBを用いたプログラムであれば、システムAPIのインターフェースは、もちろん例外はあるにせよ、基本的に一貫した形で提供されるため、リリース間の変更により強いと言える。またAPIであればスプール出力やテーブルへの書き出しがないため、より高いパフォーマンスも期待できる。

 

2.非リスト形式API

 非リスト形式はユーザー・スペース・オブジェクトへの書き出しを行うことなく、そのAPIの直接呼び出し元へパラメータとして情報を返す形式のAPIとなる。例としてはジョブ属性の取得、RTVJOBAの詳細版であるQUSRJOBIなどがある。

 RPGプログラム内でジョブの情報を取得し、ロジックで用いたい場合には、対象とする値がCLコマンドRTVJOBAを実行するCLプログラムを作成し、RPGからそのCLプログラムを呼び出すこともできるが、APIであれば直接RPGプログラム・ロジック内でその動作を完了できる。実行パフォーマンスとしてもプログラム資産の運用管理上も、APIを使うほうが効率的と言えるだろう。また、RTVJOBAはあくまで実行するジョブ自体に関する情報の取得となるが、QUSRJOBIは指定したジョブの情報を取得できる。このようにAPIはCLコマンド単体では行えないような機能が実装されているので、これを使わない手はないだろう。

 

システムAPIの解説の読み方と非リスト形式APIの利用例 

 CLコマンドよりも豊富な機能をもち、実行効率としても優れているシステムAPIだが、残念ながら実際のプログラムではそれほど多く利用されていないように見受けられる。その要因の1つに、解説やガイドの整備状況があるのではないかと筆者は考えている。

 確かにIBM iの各OSリリースのKnowledge CenterにはApplication Programming Interfaceの項目にかなりの分量の情報が用意されているが、残念なことにすべて英語での提供であり、またインターフェース定義に関しても一種独特な記載方法となっている。そこで、ここでは先に登場したAPI QUSRJOBIの解説ページであるKnowledge Centerの以下URLリンク先の記載を例にとって一緒に見ていきたいと思う。

・・・・・・・・

IBM i 7.3 Knowledge Center:Retrieve Job Information(QUSRJOBI)API http://bit.ly/api_001

・・・・・・・・

 図表2のように、解説ページの最初にはAPIを呼び出す際のパラメータ、インターフェース定義がまとめられている。このうち、「Required Parameter Group:」には呼び出す際の必須のパラメータ、「Optional Parameter Group n(nは数字)」にはオプションのパラメータが記載されている。なお「Optional Parameter Group 2」のパラメータの授受を行う場合には、より上位、ここでは「Optional Parameter Group 1」のパラメータも必ず授受しなければならない。ちょうどRPGにおけるNOPASSオプションと同様に捉えればよいだろう。またパラメータの説明としてパラメータの意味、入出力の種別(入力専用、出力専用、入出力共用)、データ型がまとめられている。ILE RPGでは、この情報を基にAPIのプロトタイプ定義を記述することになる。

 

 

 システムAPIは、使用されるプログラム言語としてRPGのみを想定しているわけではないため、RPGにおけるデータ型と一致した記述にはなっていない。システムAPIのパラメータとしてよく出てくるデータ型をILE RPGで表したものをまとめたのが、図表3となる。ILE RPGの列には、フリーフォームでの記述方法とともに、固定フォームでの形式をまとめている。Binary(4)は整数型の10桁として定義すればよく、符号なしの場合も符号なし整数型の10桁とすればよい。またChar(*)に関しては、適当なバイト長のCHAR型で*VARSIZEオプションをつける形でよい。

 

 

 また、種別が入力のパラメータに関してはCONSTオプションをつけることで、そのパラメータが入力専用であることを明記しておくとよいだろう。

 システムAPI実行時のエラー・ハンドリングとしては、「Optional Parameter Group 1」にあるError Codeに適切なデータ構造を渡すことで、エラー時のデータを得られる。データ形式としては、図表4にまとめたとおりである。多くのシステムAPIでは、この形式でのエラー・データの受け渡しとなるので覚えておくとよいだろう。特に1番目のBinary(4)の入力パラメータ値に0を明示指定することで、システムAPI実行時に*ESCAPEメッセージとしてメッセージを出せる。そうすることで、システムAPIでの実行時やエラー時の挙動を、これまでのRPGプログラムにおけるエラー・ハンドリング(MONITORなど)に任せることも可能だ。

 

 

 次にページを読み進めると、「Authorities and Locks」として実行時に必要となる権限情報などがまとめられている。API QUSRJOBIの場合には、取得したい情報の形式によっては特殊権限*JOBCTLが必要になってくる旨などが記載されている。

 その下には先ほどのパラメータ定義の詳細が、各パラメータ単位で記述されている。「Required Parameter Group」の部分を見ると、出力としてのReceiver variable、入力としてのLength of receiver variableとFormat nameの3つが定義されている。

 これらのパラメータは、それぞれ以下の意味をもつ。

 

●Receiver variable:APIで取得した情報・データを格納するための変数の集まり(RPGではデータ構造として授受可能)

●Length of receiver variable:Receiver variableの長さ

●Format name:APIがReceiver variableにデータを格納する際の形式の名称

 

 情報取得系のAPIでは、基本的にこの3つのパラメータがセットで用意されている。取得したい情報の入れ物とその大きさ、APIで入れ物に入れるデータの形式を指定するという手順を押さえておけばよいだろう。

 Format nameに格納データの形式名称を指定するのだが、形式名称と具体的な形式についてもシステムAPIの解説ページにまとめられている。QUSRJOBIでは形式のバリエーションも多く用意されており、JOBI0100からJOBI1000まで実に12もの種類がある。そのうち、QUSRJOBIでRTVJOBAのように現行ジョブの情報を取得したいなら、JOBI0600を選択すればよい。形式JOBI0600の詳細についても、以下URLリンク先のQUSRJOBIの解説ページ内にまとめられている。

・・・・・・・・

IBM i 7.3 Knowledge Center:JOBI0600 Format http://bit.ly/api_002

・・・・・・・・

 形式JOBI0600を用いると非常に多くのデータが得られる。一例として、ジョブの現行ユーザーを取得したいとする。その場合は、1つ目の「Number of bytes returned」から「Current user profile」までを指定したデータ構造を用意して、QUSRJOBIに渡せばよい。この現行ユーザー・プロファイルを取得する場合のコード例が、サンプル1である。

 

C言語形式システムAPIの解説の読み方と
IFS関連APIの利用例 

 ここまで非リスト形式APIであるQUSRJOBIを例にとって見てきたが、システムAPIのマニュアルには、これまで解説したのとは異なる表記でまとめられているシステムAPIも存在する。例として、IFS関連のAPIなどが挙げられる。CLコマンドのCPYFRMIMPFやCPYTOIMPFを、QCMDEXCやQCAPCMDを用いてRPGプログラムから呼び出すこともできるが、その場合、あくまで定形式(CSVやタブ区切りなど)データを含むファイルへの読み込み、または書き出しが対象である。一方、IFS関連のシステムAPIを用いることで、RPGでもIFS上の任意の形式のファイルを読み込んだり、ファイルに対して書き出したりといったさまざまな処理を行えるようになる。

 ここでは、IFS関連のシステムAPIであるopen()、read()、write()、close()などのAPIを例に、C言語形式システムAPIのマニュアルの読み方を見ていこう。システムAPI open()(IFSファイルのオープン)の解説は、Knowledge Centerの以下のURLリンク先にまとめられている。

・・・・・・・・

IBM i 7.3 Knowledge Center:open()–Open File http://bit.ly/api_003

・・・・・・・・

 図表5のように、open()に関してもAPI QUSRJOBIと同じくページの先頭にはパラメータ、インターフェース定義がまとめられている。ILE RPGでは、この定義をもとにプロトタイプ定義を記述すればよいことになる。ただしこのパラメータ定義だが、QUSRJOBIとは表現が大きく異なっていることにお気づきだろう。

 

 

 API open()に代表されるようなC言語形式システムAPIのパラメータ定義は、どのようにRPGで表現すればよいだろうか。表現例をまとめたものが、図表6である。なお、APIによってはパラメータを参照渡しではなく、値渡しで定義しなければならない場合もある。RPGにおけるプロシージャー・パラメータは参照渡しが基本となるため、値渡しの場合には、そのパラメータの定義にVALUEオプションを付けておけばよい。

 

 

 また、「char *」と表記されているパラメータをもつC言語形式APIも多い。この表記に対するILE RPGの表現は、大きく分けて3種類あるので注意が必要だ。

 1つ目は、パラメータ長がわかっていて、文字列のポインタを渡すケースである。この場合は単純にCHAR型の変数を参照渡しとして定義すればよいので、「CHAR(n)」と定義すればよい。なお入力専用であれば、CONSTオプションを付ける形だ。

 2つ目は、他のパラメータの指定によって長さが決まる文字列のポインタを渡すケースである。この場合、「CHAR(n)OPTIONS(*VARSIZE)」と定義する。

 3つ目のケースは、ヌル終端文字列(null-terminated)を渡すケースである。ヌル終端文字列とは文字どおり、 x’00’(null)で終了位置を判別する文字列で、C言語ではよく利用される。このパラメータはILE RPGでは、「POINTER VALUE OPTIONS(*STRING)」として定義すればよい。*STRINGオプションにより、パラメータとして値が引き渡される場合にヌル終端として確実に渡される。

 スカラー値とchar*について見てきたが、その他の表記に関するILE RPGでの表現例は、以下URLリンク先にまとめられているので、使用したいAPIのパラメータとして現れてきた場合には適宜参照されたい。

・・・・・・・・

IBM developerWorks RPG Cafe:Converting C Prototypes to RPG http://bit.ly/api_0045

・・・・・・・・

 ここまでAPI、open()を例にとり、Knowledge Centerの情報を読み解いて、ILE RPGにおいてどのようにプロトタイプ定義を記述すればよいかについて見てきた。実はこれらAPIをILE RPGから呼び出す際のプロトタイプ定義は、図表7に示すとおり、ライブラリーQSYSINC/QRPGLESRCにまとめられている。これらは/COPYで取り込むこともできる。

 

 

 IFS関連APIであれば、メンバーIFSを取り込めばよい(なおAPI QUSRJOBIについても同様に用意されている)。ライブラリーQSYSINCは、IBM iOSの無償オプションである5770SS1 Option 13 オープンネスを導入すると作成される。

 同じシステムAPIでも、C言語形式APIはパラメータ定義が異なることがわかったが、エラー・ハンドリングも異なってくる。C言語形式APIではAPI実行時エラーが発生した際、戻り値を返すが、エラー番号は別途取得が必要となる。IFS関連APIの場合、エラー時はエラー内容に関わらず、戻り値として「-1」が返ってくる。エラー詳細を把握するには、エラー番号の取得が不可欠だ。

 このエラー番号の取得には、ILE C __errno()関数を利用する。__errno()はエラー番号のポインタを戻すので、ILE RPGではこのポインタ位置から整数でエラー番号を取得できる。この__errno()関数のプロトタイプ定義も、QSYSINC/QRPGLESRCのメンバーERRNOに「getErrnoPtr」として定義されている。そのため、メンバーERRNOを/COPYで取り込んで使用すればよい。

 サンプル2はあえて/COPYで取り込まずに、自身のRPG内で定義した場合のAPI open()でのエラー・ハンドリング例となる。エラー番号用の変数としてint(10)のerrnoを定義している。このerrnoはbased(errnoPtr)で定義しているが、これは、ポインタerrnoPtrの位置から4バイトでint型変数にするという意味になる。

 では、実際にはどのようにIFS関連APIを用いて、ILE RPGでのIFSストリーム・ファイルの操作を実装すればよいだろうか。APIを用いたIFSストリーム・ファイルの読み込み・書き出し手順は、大きく以下の3ステップとなる。

 

1.API open()によるストリーム・ファイルのオープン

 ILE RPGにおけるopen()のプロトタイプ定義はサンプル3のとおりで、図表8が各パラメータの意味となる。なお、「*cwiden」は値がワイドニング(パラメータ拡大)で渡される、もしくは戻り値として受け取ることを指定するキーワードとなるが、C側で「#pragma argument(nowiden)」の指定がないものは基本的に*cwidenとなる。詳細は既出のIBM developerWorks RPG Cafe:Converting C Prototypes to RPGを参照されたい。

 

 

 open()の戻り値は、ファイル記述子(file descriptor)と呼ばれるオープンしたファイルを意味するINT(10)の整数となる。オープンに失敗すると、戻り値として「-1」が戻される。なお、oflagやmodeはビットの組み合わせの結果の値を渡す形となっている(UNIXやLinuxでのファイルに対する権限指定の考え方と同じである)。oflag、modeに指定可能な値の一例をそれぞれ図表9図表10にまとめているが、これらの定数値はプロトタイプ定義と同じくQSYSINC/QRPGLESRC内のメンバーIFSに定義されているので、/COPYで取り込むとよいだろう。

 

 

 

 

2.API read()によるファイルの読み込み

 もしくは API write()によるファイルへの書き出し

 サンプル4がread()のプロトタイプ定義で、パラメータの意味をまとめたのが図表11となる。write()に関しても同様にサンプル5図表12にプロトタイプ定義、パラメータの意味をまとめている。

 

 

 いずれに関してもopen()で取得したファイル記述子を渡し、ファイルの読み込みもしくはファイルへの書き出しを行う形だ。読み込み/書き出し処理に失敗した場合には、戻り値として「-1」が返ってくる。正常に処理が行われた場合には実際に読み込んだ、もしくは書き出したデータのサイズが返ってくる。

 

3.API close()によるファイルのクローズ

 サンプル6ならびに図表13が、close()のプロトタイプ定義とパラメータの意味となる。読み込みもしくは書き出しが終了したファイルのファイル記述子を渡すことで、クローズする。なお、1ジョブ当たり同時にオープン状態にできるファイル記述子の最大数は、システムのデフォルトでは200となっている(PASE環境では2000となる)。そのため、使い終わったファイル記述子については必ずクローズ処理を行うことが大切だ(要件に応じてAPI DosSetRelMaxFH()を用いて
1ジョブ当たりのファイル記述子の最大数自体を拡張することはできる)。

 

 

 最後にこれら3つのステップを踏まえて、CCSIDが1208(UTF-8)の既存ファイル/home/nakamura/test.txtからデータを読み込んで、新規にCCSIDが1208(UTF-8)の/home/nakamura/test2.txtを作成し、text.txtから読み込んだデータを書き出すような処理を実装するプログラム例を、サンプル7に示す。

 

ILE RPG組み込みSQLの活用Tips

 IBM iの根幹はデータベース(DB2 for i)にあるとよく言われるが、DB2 for i はOS内の種々の機能の中でもOSリリース、Technology Refreshを経るごとに着実に機能強化が図られている。DB2 for i の機能強化の一部として、SQLに関する機能拡張も大いに加えられている。RPGプログラムからも、このSQLに関する豊富な機能強化点を活用しない手はない。

 RPGからデータベースにアクセスする方法としては、レコード・レベル・アクセスのほかにSQLアクセスがあり、後者は組み込みSQLとして提供されている。ここではILE RPG組み込みSQLでも活用が可能なSQLの以下の機能拡張点について紹介したい。

 

1.SQL記述子でのパラメータ受け渡しサポート(IBM i 5.4~)

 SQLには、 SQL記述子域すなわちSQLDA(SQL Descriptor Area)と呼ばれる構造があり、あらかじめ決められたメモリ領域に対して値を出し入れする機能が用意されている。このSQL記述子域に対して付ける名称を、SQL記述子名と呼んでいる。

 このSQL記述子はプログラム内でのみ利用可能にすることもできるが、あるSQLセッション内でプログラムやプロシージャーをまたいで共有可能にすることもできる。後者のSQL記述子の機能を利用すると、一方のSQLストアード・プロシージャーでSQL記述子域に値をセットし、他方のSQLストアード・プロシージャーでそのSQL記述子から値を取り出して利用することが可能だ。

 なお、この機能はSQLストアード・プロシージャー間でのみ利用可能なわけではなく、ILE RPG組み込みSQLとSQLプロシージャー(外部プロシージャーを含む)間でも活用できる。この機能は、パラメータ・マーカーの数が可変の動的SQLステートメントによる照会実行時などに威力を発揮する。

 たとえばユーザーが指定した1つ以上の部門コードに対応する部門名および部長の社員IDを部門テーブルからリストとして照会するような処理を考えてみよう。ユーザーAは2つの部門コードを指定するが、ユーザーBは4つの部門コードを指定するといったケースである。

ユーザーAによるSQLステートメントは、

<ユーザーA>
SELECT 部門名、部長社員ID
 FROM 部門テーブル
 WHERE 部門コード IN(コード1、コード2)

 

となるだろうし、ユーザーBによるSQLステートメントは、

<ユーザーB>
SELECT 部門名、部長社員ID
 FROM 部門テーブル
 WHERE 部門コード IN(コード1、コード2、コード3、コード4)

 

となる。このようなSQLステートメントをILE RPG組み込みSQLで実行する場合、サンプル8のように部門コードをSQLステートメントのリテラルに文字列結合する形でSQLステートメントを組み上げて、実行することもあるだろう。その場合、ユーザー入力の文字列をSQLステートメントに組み込むことによるSQLインジェクションへの対策が必要になる。

 一方で、パラメータ・マーカーを利用した動的SQLステートメントとして実行することを考えると、準備するステートメントは以下のようになる。

<ユーザーA>
SELECT 部門名、部長社員ID
 FROM 部門テーブル
 WHERE 部門コード IN (?,?)

 

<ユーザーB>
SELECT 部門名、部長社員ID
 FROM 部門テーブル
 WHERE 部門コード IN (?,?,?,?)

 

 この場合、サンプル9のようにパラメータ・マーカー数の違いがあることから、マーカー数に応じたカーソルのオープン処理を行う必要が生じる。

 パラメータ・マーカーの個数のバリエーションが数個程度であれば、サンプル9のような分岐ロジックでもよいかもしれないが、ある程度の個数となってくると対応が難しい。このようなケースに活用できるのが、SQL記述子だ。

 SQL記述子域にはパラメータの個数とともに、各パラメータのデータ型、長さ、値をそれぞれ指定して格納できる。そこでサンプル10にあるように、

●最初に指定されたコード数分の値が格納できるSQL記述子を宣言
●SQL記述子内にデータ型とともに値を格納
●SQLステートメントに指定されたコード数分のパラメータ・マーカーである「?」を加えて、動的SQLステートメントの文字列を成形
●動的SQLステートメントを準備
●カーソルを宣言
●カーソルのオープン時に用いるパラメータ・マーカーの値はSQL記述子に格納された値を利用

という流れでロジックを組むと、パラメータ・マーカーの個数が不定であってもマーカー数による分岐も必要がなくなり、SQL照会処理を実装できる。

 このようにSQL記述子を活用することでILE RPGプログラムから冗長なコードを削減し、照会ロジックの共通化を図ることが可能になる。実はこの機能、現在の最新OSリリースであるIBM i 7.3から数えて5世代前のリリースであるIBM i 5.4から利用可能である。以下のURLリンク先のKnowledge CenterにあるSQL解説書に情報が記載されているので、ぜひ参考にして、活用してほしい。

・・・・・・・・

IBM i 7.3 Knowledge Center:SQL解説書 http://bit.ly/api_005

・・・・・・・・

 

2.SQL結果セットの受け渡しサポート(IBM i 7.1~) 

 IBM i 7.1からは、SQLプロシージャーの実行結果セットを呼び出し元に受け渡すことが可能になっている。呼び出し元のILE RPG側では、SQLデータ・タイプの1つである結果セット・ロケータ変数を宣言し、ロケータ変数をSQLプロシージャーの実行結果セットに関連付ける形式だ。これによりサンプル1112のように動的SQLステートメントの準備からカーソルの宣言、オープンまでをSQLプロシージャー(ILE RPGを用いたSQL外部プロシージャーでももちろん可能だ)で実装することで、SQL処理組み込みにおける処理のさらなる共通化が図れるようになる。

 

ILE RPGとSQLを活用しよう 

 PartⅡでは、ILE RPGでアプリケーション開発を進めるにあたっての機能的なTipsとしてシステムAPIの活用と、組み込みSQLでのTipsに焦点を当てて紹介した。システムAPIではKnowledge Centerの読み方、システムAPIをILE RPGから呼び出す方法について見てきた。

 本稿ではAPI QUSRJOBI、IFS関連APIという機能面で言えば比較的ベーシックで、かつCLコマンドでも代用がきくようなものを例にとっているが、システムAPIとしては非常に多くのものが用意されている。

 たとえば、IFS関連APIを使用してファイルを生成、オープンソースのzip(これは無償ライセンス・プログラムである5733-OPS Option 3 GCCを導入、構成することで利用できる)を用いてパスワード付きの圧縮ファイルを作成し、API QtmsCreateSendEmailを利用して添付ファイル付きメールとして送信するといった処理を、ILE RPGで完結して実装することもできる。

 暗号化に関しても同様だ。暗号化サービスAPIとして暗号/復号用のAPIが用意されているので、AES-256やTDESといったデータ暗号化もILE RPGで問題なく実装できる。もちろんハッシュの計算なども、ILE RPGでハンドリングできる。

 組み込みSQLに関しても、SQL記述子や結果セット・ロケータを用いた結果セットのSQLプロシージャーからの受け取りなど、より効率的に開発が進められるような機能が充実している。ぜひ読者のシステムでも、常に進化を続けているILE RPGならびにSQLを、これからも積極的に活用していただきたい。

 

・・・・・・・・

著者◎中村 陽一

日本アイ・ビー・エム システムズ・エンジニアリング株式会社
セキュリティー&コネクティビティー

[i Magazine 2016 Summer(2016年5月)掲載]

 

◎関連記事

RDiの特徴と開発の流れ ~IBM iアプリケーション開発 最新事情 PartⅠ

More Posts