IBM Support

IBM Java Toolbox for i 使用PCML远程调用RPG

Technical Blog Post


Abstract

IBM Java Toolbox for i 使用PCML远程调用RPG

Body

相对与传统的绿屏IBM i应用,现代的很多IBM i应用都基于Web技术,即前端采用基于Web的图形用户界面,后端重用传统的RPGCOBOL业务程序。如何实现软件复用,是IBM i应用现代化的一个重要目标。一方面,基于Web Service技术的IBM Integrated Web Services for i服务器可将传统RPGCOBOL应用发布成Web Service,实现软件重用;另一方面,作为基于IBM iJava应用程序编程接口,IBM Java Toolbox for i可通过相关编程接口调用RPGCOBOL,同样实现了软件重用的目标。Program Call Markup Language (以下称PCML),作为IBM i服务器端程序参数的XML描述语言,大大简化了Web ServiceIBM Java Toolbox for i的客户端编程模型。本文的主要目标是,指导读者如何使用IBM Java Toolbox for i编程模型,结合PCML语言,实现重用传统RPGCOBOL业务程序。Web Service及其相关技术不在本文讨论的范围之内。有关IBM Java Toolbox for i的基础知识,请参见另一篇技术文档“Toolbox for Java JTOpen”

 

从内容上,本文主要分为3部分。第一部分主要介绍PCML相关的基础知识,包括PCML的概念,语法,使用方法等。在第二部分中,我们将围绕IBM Java Toolbox for i相关的PCML类,结合样例,调用RPG程序,实现软件复用的目标。性能优化也是这一部分的重点内容之一。最后一部分是总结。

 

作为样例,‘用户身份查询’RPG程序RTVSTS.PGM的业务逻辑是根据输入的用户ID号,查询数据库,返回对应的身份信息。

 

PCML

作为一种基于XML的标记语言,PCML的设计目标是描述IBM i服务器端程序的输入输出参数,减少客户端程序调用的代码。

 

作为示例,清单1描述的是‘用户身份查询’RPG程序对应的输入输出参数。输入参数custid表示用户的查询ID,而输出参数status则表示身份信息查询的返回结果。

清单1. PCML样例 — 描述用户身份信息

<pcml>

   <program name="rtvsts" path="/QSYS.lib/DEMO.lib/RTVSTS.pgm">

      <data name="custid" usage="input" type="int">

      <data name="status" usage="output" type="char" length="20">

   </program>

</pcml>

 

从语法角度,PCML的根标签是<pcml>,主要嵌套以下3种标签:

 

作为示例,清单2简单地描述上述4种标签的基本用法。

清单2. PCML样例 — 标签用法

<program>

    <struct>

        <data> </data>

    </struct>

        <data> </data>

</program>

 

在理解PCML的基本概念与用法之后,我们介绍如何使用CL命令为指定IBM i程序生成PCML文档。

要生成PCML文档,只需要在使用CL命令Create Bound RPG Program (CRTBNDRPG)编译RPG程序时,指定参数PGMINFOINFOSTMF即可。样例RPG程序RTVSTS.PGM生成PCML的命令如下:

CRTBNDRPG PGM(DEMO/RTVSTS) SRCFILE(DEMO/QRPGSRC) SRCMBR(RTVSTS) PGMINFO(*PCML) INFOSTMF(/demo/pcml/rtvsts.pcml)

 

刚才,我们简单介绍了PCML的概念,设计目标,语法,与使用方法。接下来,我们将结合IBM Java Toolbox for i,实现基于PCMLIBM i程序调用。

 

IBM Java Toolbox for i结合PCML调用RPG

前面提到,使用PCML可以简化IBM Java Toolbox for i程序调用相关的Java代码。下面,我们结合样例,对比IBM Java Toolbox for i的普通程序调用与PCML程序调用的异同。

IBM Java Toolbox for i程序调用

1演示的是IBM Java Toolbox for i程序调用的工作原理。从面向对象程序设计的角度,IBM Java Toolbox for i通常使用ProgramCallServiceProgramCall类调用IBM i程序,对应的程序类型分别为*PGM*SRVPGM。输入输出参数封装成ProgramParameter类。IBM i返回程序调用的错误消息由AS400Message数组表示。

图 1. IBM Java Toolbox for i程序调用的工作原理

图像

 

 

 

 

 

 

 

 

 

 

 

作为示例,清单1描述的是‘用户身份查询’RPG应用的ProgramCall程序调用。作为IBM Java Toolbox for i程序调用的另一种方式, ServiceProgramCall的工作原理与此类似,这里不加讨论。

清单1. ProgramCall样例 — 查询用户身份信息

// 构造AS400对象,建立Java应用程序与IBM i服务器的连接。

AS400 sys = new AS400("mySystem.myCompany.com", "myUser", "myPassword");

ProgramCall pgm = new ProgramCall(sys);

pgm.setProgram("/QSYS.LIB/DEMO.LIB/RTVSTS.PGM");

 

ProgramParameter[] parmList = new ProgramParameter[2];

// 第一个参数类型为Input,输入客户的ID

parmList[0] = new ProgramParameter(custid);

// 第二个参数类型为Output,返回客户的身份信息

parmList[1] = new ProgramParameter(20);

pgm.setParameterList(parmList);

// 调用相应的run方法,从而远程调用IBM i服务器端RPG程序。

if (pgm.run()){

   // 程序结果返回给ProgramParameter的Output参数输出。

   byte[] data = parmList[1].getOutputData();

   // 调用IBM Java Toolbox for i支持转码的相关帮助类,获取用户的身份信息。

   String status = (String) textConverter.toObject(data);

} else {

   // 如果调用失败,则将错误消息封装成相关Java类AS400Message。

   AS400Message[] messageList = pgm.getMessageList();

   // ... 处理消息列表

}

// 作为好的编程习惯,释放连接

sys.disconnectService(AS400.COMMAND);

 

可以看出ProgramCall的代码量与IBM i程序的参数个数以及复杂程度是成正比的。程序参数越多,程序调用对应的源代码就越长。而基于PCML的程序调用机制的核心思想就是将这些输入输出参数的描述从Java代码向XML代码转移。当程序参数越多时,PCML的优势就越明显。

PCML程序调用

2演示的是IBM Java Toolbox for i基于PCML程序调用的工作原理。从面向对象程序设计的角度,IBM Java Toolbox for i通常使用ProgramCallDocument类结合PCML调用IBM i程序。输入输出参数封装成ProgramCallDocument类的setValue/getValue方式。

2. PCML程序调用的工作原理

图像

 

 

 

 

 

 

 

 

 

 

作为示例,清单2描述的是结合PCML调用‘用户身份查询’RPG程序。

清单2.  PCML样例 — 查询用户身份信息

// 构造AS400对象,建立Java应用程序与IBM i服务器的连接。
AS400 sys = new AS400("mySystem.myCompany.com", "myUser", "myPassword");

// 指定PCML路径(用Java包路径表示)
ProgramCallDocument pcml = new ProgramCallDocument(sys, "demo.pcml.rtvsts");
pcml.setValue("rtvsts.custid", custid);

// 调用相应的run方法,从而远程调用IBM i服务器端RPG程序。
if ( pcml.callProgram("rtvsts") ){
   // 获取用户的身份信息。
   String status = (String)pcml.getValue("rtvsts.status");
} else {
   // 如果调用失败,则将错误消息封装成相关Java类AS400Message。
   AS400Message[] messageList = pcml.getProgramCall().getMessageList();
   // ... 处理消息列表
}

// 作为好的编程习惯,释放连接
sys.disconnectService(AS400.COMMAND);

 

对比上述两种IBM i程序调用方式,可以看出,PCML的确起到了简化Java代码的作用,提高了程序的可读性。当IBM i程序的参数比较冗长,复杂时,这种优势愈发明显。但是,由于PCML是一种XML技术,PCML的解析势必会降低程序的性能。与此同时,PCML文档的调试也是一件相对麻烦的事情。下面,我们将分别介绍PCML的一些优化措施与调试手段和技巧。

 

PCML程序优化

一方面,PCML的解析是一件费时的操作,涉及Java对象与XML标签的映射。另一方面,Java支持对象的序列化。为提高效率,我们可以在编译期间,将PCML文档序列化,这样,程序运行期间,IBM Java Toolbox for i只需将PCML反序列化为Java对象,绕过了XML解析器的干预,提升了程序运行性能。

要序列化PCML文档,可以选择下列两种方式:

  • 基于命令行:

          java com.ibm.as400.data.ProgramCallDocument -serialize rtvsts         

  • 基于Java应用程序:

          ProgramCallDocument pcml = new ProgramCallDocument(sys, "demo.pcml.rtvsts");
          pcmlDoc.serialize();

从文件扩展名的角度,序列化之前的PCML源文件对应的扩展名为pcml,而序列化之后的文件扩展名为.pcml.ser。

 

PCML调试

PCML文件描述的数据结构非常复杂时,使用ProgramCallDocument类调用PCML极易出错。这里建议使用IBM Toolbox for Java提供的Trace功能,追踪PCML的调试信息,代码如下:

Trace.setTraceOn(true); // 打开全局的Trace功能

Trace.setTracePCMLOn(true); // 打开PCML的Trace功能

 

默认情况下,Trace类会将PCML相应的日志打印到System.out。当然,你也可以通过Trace类的setFileName()方法将输出重定向到文件输出。

至此,我们分别从PCML的概念,工作原理,编程方法,性能调优,调试的角度,完整介绍了如何使用IBM Java Toolbox for i实现基于PCMLIBM i程序调用。

 

总结

作为IBM i程序输入输出参数的XML描述,PCML被广泛用于Web ServiceIBM Java Toolbox for i。而IBM Java Toolbox for iPCML的支持非常全面,既包括基于PCMLIBM i程序调用,还提供有PCML的调试,以及性能优化等功能。

 

参考资源

 

作者:皮光明

 

[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB57","label":"Power"}}]

UID

ibm11144942