使用WebSphere Studio Application Developer、gSOAP和Dev-C++为WebSphere Web服务新建一个C/C++客户机
内容
引言
下载并安装 gSOAP 工具
安装 gSOAP WSDL importer 工具
准备一个输入 WSDL 文件
生成 C/C++ 组件和一个客户机
定制主要的 C/C++ 客户机
生成 Windows 控制台应用程序或 DLL
结束语
Nay Lin
顾问软件工程师,WebSphere Enablement Team
IBM Customer Solutions Center,加利福尼亚圣地亚哥
2003 年 1 月
? Copyright International Business Machines Corporation 2003. All rights reserved.
引言
WebSphere? Studio Application Developer(以下称为 Application Developer)为快速从现有 J2EE 组件构建 SOAP/XML Web 提供向导,例如从会话 EJB 和 Java? bean 组件来构建。Application Developer 能为任何 Java 客户机或 WSDL 文件生成一个 Java 客户机代理,只要这些文件能被其它供应商用来构建 Web 服务客户机。
某些情况下,您也许需要一个非 Java 客户机来使用 J2EE Web 服务。您可以使用 Microsoft? .NET 框架提供的 wsdl.exe 工具来为 WebSphere Web 服务生成一个 C# 或 Jscript 客户机。或者,一些开放源代码工具能为在不同语言和操作系统中生成客户机提供便利。(这里有 SOAP 软件工具清单)。
开放源代码工具之一的 gSOAP 提供一种独特的 SOAP/XML 到 C/C++ 语言绑定,以简化 C 或 C++ 中 SOAP/XML Web 服务和客户机的开发。gSOAP 工具包括一个 WSDL 生成器,用于为您的 Web 服务生成 Web 服务描述。WSDL importer 工具使 SOAP 客户机应用程序开发完全自动化。
使用 Application Developer 和 gSOAP 编译器、C/C++ 和 Fortran 下的客户机(经由一个 Fortran 连接到 C 接口)以及 4GL 客户机,例如 PowerBuilder(通过一个 C++ DLL),就能通过 WebSphere Application Server 跨平台连接作为 Web 服务公开的 J2EE 应用程序。
为相应的 J2EE Web 服务生成一个 C/C++ 客户机:
1. 使用 Application Developer 生成 Web 服务及其 WSDL 文件,以公开一个 EJB 或 Java bean。
2. 在分布式平台上的 WebSphere 4.0x/5.0 或 z/OS? 和 OS/390? 上的 WebSphere 4.01 上部署 Web 服务。
3. 使用 gSOAP WSDL importer 工具生成一个 C/C++ 客户机应用程序或 DLL。本教程描述了如何运行第 3 步,假定第 1 步和第 2 步已完成。可在本页下方下载为 Web 服务而从 Application Developer 4.02 生成并导出的名为 HelloWorld.ear 的样本企业归档(enterprise archive,EAR)文件。关于第 1 步和第 2 步的详细情况,参见 Application Developer 的联机帮助或在相关信息中列出的关于使用 Application Developer 生成 Web 服务的教程和红皮书。
下载并安装 gSOAP 工具
进入 SourceForge 网站并(对于 Windows? 工作站)下载名为 soapcpp-win32-2.1.7.zip 的 ZIP 文件。将所有文件解压缩到安装盘(比如 C:)。如要测试 gSOAP 示例和 SSL,请按照 C:soapcpp-win32-2.1.7INSTALL.txt 里的说明。
安装 gSOAP WSDL importer 工具
1. 切换到 C:soapcpp-win32-2.1.7wsdlcpp 目录,阅读 readme.txt 中关于第 1 步的说明。
2. 安装一个用于 Java 的 XML 解析器,例如 Apache Xerces 2.0.1(xercesImpl.jar 和 xmlParserAPIs.jar)或 Xerces 1.4.4(xerces.jar)。可根据需要改变类路径。WSDL 导入工具的 wsdlcpp.java 资源已为 Xerces DOM 解析器配置好了。如要使用另一个 Java DOM 解析器,请在 wsdlcpp.java 中修改 DOM 解析器类导入。
3. 使用 javac wsdlcpp.java 命令编译 wsdlcpp。
准备一个输入 WSDL 文件
此工具并不支持 <import../> 标记。这个输入 WSDL 文件一定要是独立的(参见 C:soapcpp- win32-2.1.7wsdlcppREADME.txt 文件中 Limitations 下的说明)。Application Developer 或 Application Developer Integration Edition 为每个 Web 服务 EAR 生成两个名为 <wsname> 的 WSDL 文件(比如 <wsname>-service.wsdl 和 <wsname>-binding.wsdl)。第一个文件 <wsname>-service.wsdl 导入绑定的定义 <wsname>-binding.wsdl。要将它们合并到一个文件中:
1. 复制 <wsname>-binding.wsdl 中 <definitions>...</definitions> 里的所有元素条目。
2. 编辑 <wsname>-service.wsdl,将条目 <import ../> 用上面复制的内容覆盖。
此处的示例是 Application Developer 为作为 Web 服务公开的 HellowWorld 会话 EJB 的 hello 方法而生成的两个 WSDL 文件:
清单 1.HelloWorld-service.wsdl
<definitions name="HelloWorldService"
targetNamespace="http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-service.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:binding="http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns="http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-service.wsdl">
<import location="http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-binding.wsdl"
namespace="http://www.helloworld.com/definitions/HelloWorldRemoteInterface"/>
<service name="HelloWorldService">
<port binding="binding:HelloWorldBinding" name="HelloWorldPort">
<soap:address location="http://localhost:8080/HelloWorldWebService/servlet/rpcrouter"/>
</port>
</service>
</definitions>
清单 2.HelloWorld-binding.wsdl
<definitions name="HelloWorld-binding"
targetNamespace="http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns=http://www.helloworld.com/definitions/HelloWorldRemoteInterface
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="helloRequest">
<part name="str" type="xsd:string"/>
</message>
<message name="helloResponse">
<part name="result" type="xsd:string"/>
</message>
<portType name="HelloWorld">
<operation name="hello" parameterOrder="str">
<input message="tns:helloRequest" name="helloRequest"/>
<output message="tns:helloResponse" name="helloResponse"/>
</operation>
</portType>
<binding name="HelloWorldBinding" type="tns:HelloWorld">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="hello">
<soap:operation soapAction="" style="rpc"/>
<input name="helloRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/com.ibm.hello.ejb.HelloWorld" use="encoded"/>
</input>
<output name="helloResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/com.ibm.hello.ejb.HelloWorld" use="encoded"/>
</output>
</operation>
</binding>
</definitions>
这是合并后的 HelloWorld-service.wsdl WSDL 文件样本:
清单 3. HelloWorld-service.wsdl
<definitions name="HelloWorldService"
targetNamespace="http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-service.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:binding="http://www.helloworld.com/definitions/HelloWorldRemoteInterface"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns=http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-service.wsdl
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="helloRequest">
<part name="str" type="xsd:string"/>
</message>
<message name="helloResponse">
<part name="result" type="xsd:string"/>
</message>
<portType name="HelloWorld">
<operation name="hello" parameterOrder="str">
<input message="tns:helloRequest" name="helloRequest"/>
<output message="tns:helloResponse" name="helloResponse"/>
</operation>
</portType>
<binding name="HelloWorldBinding" type="tns:HelloWorld">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="hello">
<soap:operation soapAction="" style="rpc"/>
<input name="helloRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace=http://tempuri.org/com.ibm.hello.ejb.HelloWorld use="encoded"/>
</input>
<output name="helloResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/com.ibm.hello.ejb.HelloWorld" use="encoded"/>
</output>
</operation>
</binding>
<service name="HelloWorldService">
<port binding="binding:HelloWorldBinding" name="HelloWorldPort">
<soap:address location="http://localhost:8080/HelloWorldWebService/servlet/rpcrouter"/>
</port>
</service>
</definitions>
上面的样本 WSDL 文件(以及所包含的 EAR 文件)是由 Application Developer 4.02 所生成。这里的说明适用于 Application Developer 5.0 生成的 Web 服务,只要对 <import ../> 作一致修改。
生成 C/C++ 组件和一个客户机
从 WSDL 新建代理(存根)需要两个步骤(参见 C:soapcpp-win32-2.1.7wsdlcppREADME.txt 中说明的第 2 步)。
1. 执行 Java 程序 wsdlcpp(WSDL Importer):java wsdlcpp <file>.wsdl。这将生成以下文件:
<file>.h gSOAP 编译器的头文件声明
<file>.c 一个客户机程序摸板
这里 <file> 是输入 WSDL 文件的名称。头文件将由 gSOAP 编译器处理:
2. 执行 gSOAP 编译器:soapcpp2 <file>.h
这将生成以下组件:
soapStub.h 与 <file>.h 相似的头文件,但带有数据类型注释
soapH.h soapC.cpp 的头文件
soapC.cpp C/C++ 数据类型的 SOAP/XML(反)序列化器
soapClient.cpp 远程方法调用的代理存根例程
soapServer.cpp 服务执行的框架例程
soap<srv>.wsdl 一个 WSDL 文件,<srv>是服务名
<srv>.nsmap 客户机应用程序的一个名称空间映射表
定制主要的 C/C++ 客户机(生成为 <file>.c)
修改生成的客户机以声明合适的输入和输出变量,并将这些作为参数传递给 Web 服务方法调用。您可能还想将此文件重命名为 .cpp。由于要和 C 语言兼容,返回类型定义为 struct(在 soapStub.h 中定义)。在我们的示例中,定义如下:
清单 4. 返回类型定义
struct tns__helloResponse
{
char *_result;
};
这是此工具生成的样本客户机代码 HelloWorld-service.cpp,然后进行修改(您可以将输入名称 Nay Lin 修改为您自己的名字)。
清单 5. HelloWorld-service.cpp
#include "soapH.h"
#include "soapHelloWorldService.nsmap"
#include <iostream.h>
main()
{
struct soap soap; // gSOAP runtime environment
soap_init(&soap); // initialize runtime environment (only once)
struct tns__helloResponse response;
char dummy[100];
if (soap_call_tns__hello ( &soap, "http://localhost:8080/HelloWorldWebService/servlet/rpcrouter",
"","Nay Lin", &response)== SOAP_OK)
{
cout << "HelloWorld WebService response "<<endl;
cout << "result = "<< response._result <<endl;
}
else
soap_print_fault(&soap,stderr); //display the SOAP fault message on the stderr stream
soap_end(&soap); //clean up
cout <<"Press e to end program .." <<endl;
cin >> dummy;
return 0;
}
示例头文件由 gSOAP 工具生成:
清单 6. HelloWorld-service.h
//gsoap tns schema namespace: http://tempuri.org/com.ibm.hello.ejb.HelloWorld
//gsoap binding schema namespace: http://www.helloworld.com/definitions/HelloWorldRemoteInterface
//gsoap tns service namespace: http://localhost:8080/HelloWorldWebService/wsdl/HelloWorld-service.wsdl
//gsoap tns service location: http://localhost:8080/HelloWorldWebService/servlet/rpcrouter
//gsoap tns service name: soapHelloWorldService
/*start primitive data types*/
typedef char * xsd__string;
/*end primitive data types*/
//soapAction :
tns__hello ( xsd__string str, struct tns__helloResponse {xsd__string _result; } *out) ;
生成 Windows 控制台应用程序或 DLL
要编译并运行这些 C/C++ 程序,可以使用 GNU C++ 编译器或将 C/C++ 程序导入到 Visual C++ 6.0 中。要运行这里的 HelloWorld 示例,我们使用一种简单的 Windows 平台 Dev-C++ 上的 GNU C++ IDE。您可以从 SourceForge 或 BloodShed.net 下载。如需联机帮助,您还需要定购一张便宜的 CD,它容量较小(大约 10MB),而且简单。如果您编译运行 GNU 调试器,可能会使用太多内存,或许是因为您进入一个程序呼叫时,它都试图打开一个窗口。
图 1. DevC++ IDE。
gSOAP 模块 stdsoap2.cpp 的链接需要 wsock32.dll 库。要在 Visual C++ 6.0 中安装此项:
1. 选择 File view 中的 project file,选择 Project => Settings,然后选择 Link 选项卡。
2. 将 wsock32.lib 添加到 Object/library 模块条目。要在 Dev-C++ 中添加,右键单击您的项目并选择 Project options。打开了 Project options 窗口。
3. 在 Linker Options/Optional Libs 或 Object files 区域,输入 -lwsock32。
您可以选择 Type WIN32 DLL 项目以生成一个 DLL 而不是 Dev-C++ 下的可执行文件。这是 Dev-C++ IDE Project Options 窗口的抓屏:
图 2. 配置 project options。
推荐:取消对 stdsoap.h 中下列行的注释,以打开 logging in the beginning 功能:
#define DEBUG */ /* Uncomment to debug sending (in file SENT.log) receiving (in file RECV.log)
and messages (in file TEST.log)
这样会在项目工作目录下生成 log 文件。这里有样本控制台输出,是由为访问 HelloWorld Web 服务而运行 C++ 客户机应用程序所生成的:
HelloWorld WebService response
result = HelloWorld From Nay Lin!
Press e to end program ..
结束语
本文演示了如何使用开放源代码工具 gSOAP 和 Dev-Cpp 来开发一个连接到 WebSphere Web 服务的 C/C++ 客户机。您已经学习了如何:
* 下载、安装和配置 gSOAP 以及 gSOAP Importer 工具。
* 从 Application developer 所生成的两个 WSDL 文件来准备一个 WSDL 文件。
* 生成并定制 C/C++ 客户机组件。
* 使用开放源代码 IDE Dev-C++ 生成一个 Windows 控制台应用程序或 DLL。
这些知识能帮助您从开始用 WebSphere Web 服务和开放源代码工具将 J2EE 企业应用程序和 C/C++ 应用程序集成起来。
相关信息
* Sheldon Wosnick 所写的 使用 WebSphere Studio Application Developer 开发并测试一段完整“Hello World”J2EE 应用程序
* Sheldon Wosnick 所写的 使用 WebSphere Studio Application Developer 开发并测试一段完整 J2EE 应用程序 — 第 2 部分:在 WebSphere Application Server 上运行
* Sheldon Wosnick 所写的 开发 IBM WebSphere Studio Application Developer 和 Microsoft .NET Framework SDK 支持的 Microsoft .NET Web Service Clients for EJB Web Services
* WebSphere Studio Application Developer Integration Edition -- Presentations 和 Labs
* Robert A. van Engelen 所写的 The gSOAP Stub and Skeleton Compiler for C and C++ 2.1.7
关于作者
Nay Lin 加利福尼亚圣地亚哥 IBM WebSphere Enablement team 的顾问软件工程师。他的顾问专长包括 WebSphere Application Server、WebSphere 企业编程模型扩展和使用 WebSphere Studio Application Developer 的应用程序开发。您可以通过 naylin@us.ibm.com 与 Nay 联系。
IBM、DB2、VisualAge 和 WebSphere 是 IBM 公司在美国或其它国家或地区的商标或注册商标。
Microsoft、Windows、Windows NT 和 Windows 徽标是 Microsoft 公司在美国或其它国家或地区的商标或注册商标。
Java 和所有基于 Java 的商标与徽标都是 Sun Microsystems 公司在美国或其它国家或地区的商标或注册商标。
其它公司、产品和服务名称可能是其它公司的商标或服务标志。