几年来,RPG程序员已经能够使用wsdl2ws.sh
工具发出的C存根调用Web服务。 但是,在RPG应用程序中使用C存根的过程很麻烦。 程序员需要执行以下步骤:
- 将C结构映射到RPG结构。
- 添加用于服务接口功能和操作的RPG原型。
根据WSDL文件的复杂性,第一步可能是一场噩梦。
并说您完成了上述步骤,您仍然必须处理指针并担心内存泄漏!
RPG程序员很高兴。 IBM增强了wsdl2ws.sh
工具,以便用户能够生成RPG存根。 本文提供了一个简单的示例,说明如何使用wsdl2ws.sh
工具生成的RPG存根代码创建用ILE RPG编写的Web服务客户端应用程序。
先决条件
软件
表1列出了IBM i操作系统的每个受支持版本所需要的PTF。
表1.软件先决条件
我6.1 我5.4IBM i发布 | PTFs |
---|---|
我7.1 | SI43607 |
SI43608 | |
SI43609 |
假设条件
由于该示例依赖于ConvertTemp
服务,因此您可能要按照学习Web服务服务器中所述创建一个Web服务服务器 (创建Web服务服务器时,不需要部署Web服务,我们将使用示例Web创建服务器时自动部署的服务)。 否则,运行该应用程序将导致错误。
注意 :ILE的Web服务客户端的安装目录是/QIBM/ProdData/OS/WebServices/V1/client
。 在本文中,安装目录显示为<install_dir>
。
创建使用RPG存根代码的RPG应用程序
要开发Web服务客户端应用程序,应遵循以下步骤:
- 使用
wsdl2ws.sh
命令生成客户机Web服务存根。 - 生成客户端应用程序。
- 运行客户端应用程序。
以下各节将讨论每个步骤。 为了便于说明,我们将使用产品随附的示例代码在目录<install_dir>/samples/ConvertTemp
。 表2中列出了我们将使用的文件,这些文件包含在“ 下载”部分的样本下载中。
表2.示例中使用的文件
文件 | 描述 |
---|---|
ConvertTemp.wsdl | WSDL文件。 |
ConvertTempClientWSDL2RPG.RPGLE | 用RPG编写的客户端实现代码。 |
清单1中显示的WSDL文件用于温度转换服务,该服务将温度从华氏温度转换为摄氏温度。 定义了两个操作:
- 转换温度
- converttemp_XML
converttemp
操作以摄氏度为converttemp_XML
返回温度,而converttemp_XML
操作以XML文档形式返回结果。 请注意,清单1提供了此服务的WSDL的局部视图,仅显示了converttemp
操作中涉及的部分,这是我们将在RPG应用程序中使用的操作。
清单1. WSDL定义
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl=http://schemas.xmlsoap.org/wsdl/
xmlns:ns1="http://org.apache.axis2/xsd"
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:ns0="http://converttemp.wsbeans.iseries/xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
targetNamespace="http://converttemp.wsbeans.iseries">
<wsdl:types>
<xs:schema xmlns:ns="http://converttemp.wsbeans.iseries/xsd"
attributeFormDefault="qualified" elementFormDefault="qualified"
targetNamespace="http://converttemp.wsbeans.iseries/xsd">
...
<xs:complexType name="CONVERTTEMPInput">
<xs:sequence>
<xs:element minOccurs="0" name="_TEMPIN" nillable="true" type="xs:string"/>
</xs:sequence>
<xs:complexType>
...
<xs:element name="converttemp">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="param0" nillable="true"
type="ns:CONVERTTEMPInput"/>
</xs:sequence>
<xs:complexType>
</xs:element>
<xs:element name="converttempResponse">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="return" nillable="true"
type="ns:CONVERTTEMPResult"/>
</xs:sequence>
<xs:complexType>
</xs:element>
<xs:complexType name="CONVERTTEMPResult">
<xs:sequence>
<xs:element minOccurs="0" name="_TEMPOUT" nillable="true"
type="xs:string"/>
</xs:sequence>
<xs:complexType>
</xs:schema>
</wsdl:types>
...
<wsdl:message name="converttempRequest">
<wsdl:part name="parameters" element="ns0:converttemp"/>
</wsdl:message>
<wsdl:message name="converttempResponse">
<wsdl:part name="parameters" element="ns0:converttempResponse"/>
</wsdl:message>
<wsdl:portType name="ConvertTempPortType">
<wsdl:operation name="converttemp_XML">
<wsdl:input message="axis2:converttemp_XMLRequest"
wsaw:Action="urn:converttemp_XML"/>
<wsdl:output message="axis2:converttemp_XMLResponse"
wsaw:Action="urn:converttemp_XMLResponse"/>
</wsdl:operation>
<wsdl:operation name="converttemp">
<wsdl:input message="axis2:converttempRequest" wsaw:Action="urn:converttemp"/>
<wsdl:output message="axis2:converttempResponse"
wsaw:Action="urn:converttempResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ConvertTempSOAP11Binding" type="axis2:ConvertTempPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<wsdl:operation name="converttemp_XML">
<soap:operation soapAction="urn:converttemp_XML" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="converttemp">
<soap:operation soapAction="urn:converttemp" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ConvertTemp">
<wsdl:port name="ConvertTempSOAP11port_http"
binding="axis2:ConvertTempSOAP11Binding">
<soap:address location="http://localhost:10022/web/services/ConvertTemp"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
步骤1.创建客户端存根代码
在创建Web服务客户端应用程序之前,必须首先使用wsdl2ws.sh
工具生成RPG客户端存根。 wsdl2ws.sh
工具使用传递给它的WSDL文件以及WSDL文件中引用的任何相关XSD文件来创建客户机存根。
要从WSDL源文件生成客户机存根,请完成以下步骤。
- 创建一个名为CVTTEMP的库,通过从CL命令行发出CL命令
CRTLIB
来存储程序对象,如下所示:
CRTLIB CVTTEMP
- 通过从CL命令行发出
QSH
CL命令来启动Qshell会话。 - 运行
wsdl2ws.sh
工具来生成客户机RPG存根代码,如以下示例所示:
<install_dir>/bin/wsdl2ws.sh -o/convtemp/RPG -lrpg
-s/qsys.lib/cvttemp.lib/wsrpg.srvpgm<install_dir>/samples/ConvertTemp/ConvertTemp.wsdl
如果检查该命令,则会看到我们正在向wsdl2ws.sh
工具指示应生成RPG存根代码并将其存储在目录/convtemp/RPG
,并且指示服务程序/qsys.lib/cvttemp.lib/wsrpg.srvpgm
,应使用生成的存根代码创建。
清单2显示了wsdl2ws.sh
工具生成的文件:
清单2.生成的存根文件
ConvertTempPortType_util.rpgle
ConvertTempPortType_util.rpgleinc
ConvertTempPortType_xsdtypes.rpgleinc
ConvertTempPortType.c
ConvertTempPortType.cl
ConvertTempPortType.h
ConvertTempPortType.rpgle
ConvertTempPortType.rpgleinc
CONVERTTEMPInput.c
CONVERTTEMPInput.h
CONVERTTEMPResult.c
CONVERTTEMPResult.h
请注意,除了生成RPG存根代码外,还生成了C存根代码,因为RPG存根代码是建立在C存根代码之上的。 出于所有实际目的,可以忽略C存根代码。
这是每个生成的RPG文件的描述:
- ConvertTempPortType_util.rpgle – RPG实用程序例程。
- ConvertTempPortType_util.rpgleinc –包括RPG实用程序例程。
- ConvertTempPortType_xsdtypes.rpgleinc –包括标准数据类型。
- ConvertTempPortType.rpgle – RPG Web服务实现代码。
- ConvertTempPortType.rpgleinc – RPG Web服务包括。
从RPG程序员的角度来看,您需要查看的唯一文件是
ConvertTempPortType.rpgleinc
和ConvertTempPortType_xsdtypes.rpgleinc
文件。 除了Web服务操作之外, ConvertTempPortType.rpgleinc
文件还定义了RPG函数以创建和销毁Web服务接口对象。 文件中还定义了Web服务操作所需的任何类型。 ConvertTempPortType_xsdtypes.rpgleinc
文件定义所有原始类型和各种常量。
清单3显示了ConvertTempPortType.rpgleinc
文件。
清单3. ConvertTempPortType.rpgleinc文件
* ********************************************************************
* ********************************************************************
* D A T A T Y P E S
* ********************************************************************
* ********************************************************************
D CONVERTTEMPInput_t...
D DS qualified based(Template)
D isNil_CONVERTTEMPInput_t...
D 1n
D TEMPIN likeds(xsd_string)
D CONVERTTEMPResult_t...
D DS qualified based(Template)
D isNil_CONVERTTEMPResult_t...
D 1n
D TEMPOUT likeds(xsd_string)
* ********************************************************************
* ********************************************************************
* P R O T O T Y P E S
* ********************************************************************
* ********************************************************************
* ********************************************************************
* WEB SERVICE CLIENT STUB PROTOTYPES
* ********************************************************************
* **************************************************************
* RPG Call : stub_create_ConvertTempPortType
* **************************************************************
D stub_create_ConvertTempPortType...
D PR 1N extproc('stub_create_ConvertTempPo+
D rtType@')
D this likeds(This_t)
* **************************************************************
* RPG Call : stub_destroy_ConvertTempPortType
* **************************************************************
D stub_destroy_ConvertTempPortType...
D PR 1N extproc('stub_destroy_ConvertTempP+
D ortType@')
D this likeds(This_t)
* ********************************************************************
* WEB SERVICE OPERATION PROTOTYPES
* ********************************************************************
* **************************************************************
* RPG call : stub_op_converttemp_XML
* **************************************************************
D stub_op_converttemp_XML...
D PR 1N extproc('converttemp_XML@')
D this likeds(This_t)
D Value0 likeds(CONVERTTEMPInput_t)
D out likeds(xsd_string)
* **************************************************************
* RPG call : stub_op_converttemp
* **************************************************************
D stub_op_converttemp...
D PR 1N extproc('converttemp@')
D this likeds(This_t)
D Value0 likeds(CONVERTTEMPInput_t)
D out likeds(CONVERTTEMPResult_t)
在检查清单3时,请注意以下几点:
-
ConvertTemp.wsdl
仅具有一项称为ConvertTemp
服务。 - 该服务只有一种端口类型,称为
ConvertTempPortType
。 -
ConvertTempPortType
端口类型具有两个操作,分别称为converttemp
和converttemp_XML
。 相应的RPG存根操作(在生成的ConvertTempPortType.rpgleinc
包含文件中定义)是stub_op_converttemp()
和stub_op_converttemp_XML()
。 - 该Web服务称为
ConvertTempPortType
。 因此,要获取Web服务的实例,您可以调用stub_create_ConvertTempPortType
()函数。 然后,在调用Web服务操作时应使用该函数返回的句柄。 要销毁该Web服务实例,可以调用stub_destroy_ConvertTempPortType
()函数。 (这两个函数都在生成的ConvertTempPortType.rpgleinc
包含文件中定义。)
最后,还会生成文件ConvertTempPortType.cl
。 该文件是一个CL源文件,其中包含重新创建包含存根代码的服务程序所需的CL命令。 您可以将此源文件复制到源物理文件并创建一个CL程序。
步骤2.构建客户端应用程序
生成客户端存根之后,可以使用存根创建Web服务客户端应用程序。
清单4显示了使用已创建的RPG存根来调用converttemp
Web服务操作的RPG客户端应用程序。
清单4.使用生成的RPG存根的RPG应用程序
h DFTNAME(CVTTEMP)
*
/copy ConvertTempPortType.rpgleinc
d OutputText s 50
d WsStub ds likeds(This_t)
d Input ds likeds(CONVERTTEMPInput_t)
d Result ds likeds(CONVERTTEMPResult_t)
*--------------------------------------------------------------------
* Program entry point. The input parameter is a character field
* representing the temperature in Fahrenheit.
*--------------------------------------------------------------------
C *ENTRY PLIST
C PARM TEMPIN 32
*--------------------------------------------------------------------
* Web service logic. The code will attempt to invoke a Web
* service in order to convert temperature in Fahrenheit to Celsius
* and then display the results.
*--------------------------------------------------------------------
/free
// Get a Web service stub. The host and port for the endpoint may need
// to be changed to match host and port of Web service. Or you can pass
// blanks and endpoint in the WSDL file will be used.
clear WsStub;
WsStub.endpoint = 'http://localhost:10000/web/services/ConvertTemp';
clear input;
Input.TEMPIN.value = %trim(TEMPIN);
if (stub_create_ConvertTempPortType(WsStub) = *ON);
// Invoke the ConvertTemp Web service operation.
if (stub_op_ConvertTemp(WsStub:Input:Result) = *ON);
OutputText = Input.TEMPIN.value + ' Fahrenheit is '
+ Result.TEMPOUT.value + ' Celsius.';
else;
OutputText = WsStub.excString;
endif;
// Display results.
dsply OutputText;
// Destroy Web service stubs.
stub_destroy_ConvertTempPortType(WsStub);
endif;
*INLR=*ON;
/end-free
要构建客户端应用程序,请完成以下步骤。
- 将当前工作目录更改为RPG存根代码的位置。 从CL命令行发出以下命令:
cd '/convtemp/RPG'
- 通过从CL命令行发出以下命令,将使用产品示例目录生成的存根代码的示例RPG代码复制到当前工作目录:
COPY OBJ('<install_dir>/samples/ConvertTemp/ConvertTempClientWSDL2RPG.RPGLE')
TODIR('/convtemp/RPG') - 如果已创建Web服务服务器,则在上一步中复制的文件中更改端点的服务器名称和端口号,以匹配服务器和服务器中安装的
ConvertTemp
Web服务的端口。 文件中的端点是:
'http://localhost:10000/web/services/ConvertTemp'
- 通过从CL命令行使用以下命令来构建客户端应用程序:
CRTRPGMOD MODULE(CVTTEMP/CNVRTTEMP)
SRCSTMF('/convtemp/RPG/ConvertTempClientWSDL2RPG.rpgle')
CRTPGM PGM(CVTTEMP/CNVRTTEMP)
MODULE(CVTTEMP/CNVRTTEMP)
BNDSRVPGM(QSYSDIR/QAXIS10CC CVTTEMP/WSRPG)
步骤3.运行客户端应用程序
完成编码和构建Web服务客户端应用程序后,运行并测试客户端应用程序。 通过从CL命令行发出以下命令来运行客户端应用程序(在此示例中,我们要找出摄氏5度是多少摄氏度):
CALL CVTTEMP/CNVRTTEMP '5'
检查客户端应用程序是否显示上面使用的华氏值的摄氏度表示。 下面的图1中的示例屏幕快照显示了从命令行运行的客户端应用程序(请注意,要查看结果,您需要按“ F10 =包括详细消息”功能键):
图1.调用客户端应用程序
摘要
从RPG程序员不得不弄清楚如何使用C Web服务存根开始,生成RPG Web服务存根的能力是一个巨大的飞跃。 那你还在等什么?
资料下载
ConvertTempClientWSDL2RPG.RPGLE
翻译自: https://www.ibm.com/developerworks/ibmi/library/i-amrawsdl2rpg/index.html