扫二维码关注kmpro
KMPRO
站内搜索
 位置:首页>知识管理实施>IT实施阶段>

无SOAP的Web服务,第二部分 来源:   时间:2002-08-27 10:34   作者:AMTeam.org

无SOAP的Web服务,第二部分

--“Web 服务调用框架”的体系结构,WSIF 的体系结构


Nirmal K. Mukhi(nmukhi@us.ibm.com),副研究员,IBM Research

Aleksandor Slominski(
aslom@indiana.edu),研究助理,IU Extreme! Lab,Indiana University

2001 年 9 月

在前面的文章中介绍了 WSIF,说明了它怎样为简化的 Web 服务调用提供独立于绑定的 API。这篇文章将看看一些高级的 WSIF 功能。这将需要对其体系结构有一个概述,接下来您将看到怎样开发多服务绑定,以及怎样给 Web 服务更新和添加新的绑定实现。

“Web 服务调用框架”(Web Services Invocation Framework(WSIF))是为调用 Web 服务提供简单 API 的工具箱,而不管服务怎样提供或由哪里提供。在前面的文章中(请参阅参考资料),我们讨论了对 WSIF 的需要、其设计背后的思想以及描述了一些主要的功能。我们比较了 WSIF 的由 WSDL 驱动的 API 和用于使用Web 服务的常规 API,并且描述了端口类型编译器和无存根调用。

WSIF 甚至还可以提供更多。其体系结构允许通过端口工厂(port factory)发现调用端口。我们可以使用定制的绑定实现进行服务调用的调用端口,并且将它们插入到框架中。我们也可以设计我们自己的端口工厂,这样使用定制的算法能够查找或创建调用端口。最后,对于消息内用到的数据,WSIF 允许我们使用任何本机类型系统。在这篇文章中,我们将描述启用这些功能的 WSIF 的体系结构方面,并且讨论利用这种灵活体系结构的特定方法。

WSIF 的体系结构

WSIF 通过以下步骤调用服务操作:

装入 WSDL 文档。

为服务创建一个端口工厂。

该端口工厂用来检索服务端口。

如果需要,通过使用根据某个本机类型系统定型的消息部件创建消息。

通过给该端口提供待调用操作的名称以及操作需要的一个输入和/或输出消息进行调用。

WSIFPort

这里关键的抽象是 WSDL 端口的运行时表示,称之为 WSIFPort。它负责在特殊绑定的基础上进行实际调用。例如,为了调用抽象服务操作,我们要有 WSIFSOAPPort,它能使用为此服务在 WSDL 中指定的 SOAP 绑定。该体系结构的灵活性集中在清单 1 中所示的 WSIFPort 接口上。

清单 1:WSIFPort 接口

public interface WSIFPort {
public boolean executeRequestResponseOperation (String op,
WSIFMessage input,
WSIFMessage output,
WSIFMessage fault)
throws WSIFException;
// some other methods not specified here
}

这个接口的实现将必须知道使用指定的抽象输入和输出消息怎样调用操作。如果基于 Apache SOAP API,WSIFPort 的 SOAP 实现可以根据来自该服务 WSDL 文档的 SOAP 绑定信息创建一个 Call 对象,然后使用抽象输入消息创建调用必需的参数。可以用 SOAP 响应来植入随后可由客户机检查的抽象输出消息。

WSIFPortFactory

WSIFPortFactory 负责检索用于特殊调用的 WSIFPort。它具有清单 2 所描述的接口。

清单 2:WSIFPortFactory 接口

public interface WSIFPortFactory {
public WSIFPort getPort () throws WSIFException;
public WSIFPort getPort (String portName) throws WSIFException;
}

请注意不带参数的 getPort 版本允许该接口实现有某个定制的算法来选择用于调用的 WSIFPort。WSIF 分发包有该接口的两个实现:静态端口工厂和动态端口工厂。静态端口工厂存储 WSIFPort 对象列表,并且当发出 getPort() 时,以伪随机方式返回其中一个对象。动态端口工厂存储动态提供者列表。这些提供者中的每一个能够根据服务的 WSDL 信息在运行时创建 WSIFPort。当在动态端口工厂调用 getPort() 时,工厂将以伪随机方式选择动态提供者,使它能创建接着返回的 WSIFPort。端口工厂体系结构的整体视图如图 1 所示。

图 1:WSIF 端口/端口工厂体系结构


WSIF 部件

到此为止我们讨论了 WSIF 端口怎样从特定的实现分离出来以及怎样用端口工厂来发现和创建端口。端口使我们能够建立调用,但是实施调用本身之前基本的一步是创建操作所需的消息。WSDL 中的消息由绑到某个类型系统的命名部件组成。典型情况下,将 XML 模式用作类型系统为 WSDL 部件定型。这独立于语言,非常强大。通过将这种模式类型映射到更方便的类型系统以及允许在属于该类型系统和模式类型的对象之间进行转换,从客户机调用这种服务。例如,当 Java 是本机类型系统时,使用设计为具有明确目的类,通过序列化和反序列化完成 Java 和模式之间的转换。

将 WSIF 的部件体系结构设计为任何本机类型系统可用于消息部件,并允许相同消息内的部件用不同的类型系统定型。在必须将来自两个或多个独立的 WSDL 消息(和不同的本机类型系统相关联)组合到单一消息中时,后者是必需的。除了允许有不同的本机类型系统,还需要有解释消息部件的通用的方法,这样就可能统一地查看 WSIF 消息对象。WSIF 采取的方法是模式为消息部件所用的标准抽象类型,并且所有这样的模式类型有相应的 JavaBean(可以使用将模式转换到 Java 的规范映射进行定义)。这给出了 WSIF 部件通用的类型系统。因此 WSIFPart 接口看似如清单 3 所示。

清单 3:WSIFPart 接口

public interface WSIFPart {
public Class getJavaType ();
public Object getJavaValue ();
}

只要能将这些表示转换为相应的规范 Java 类型,该接口的特定实现就可以使用任何一个内部类型系统。由 WSIF 提供的唯一 WSIFPart 接口实现是使用 Java 作为类型系统的 WSIFJavaPart。还有别的实现能够利用通用使用模式来提高效率。例如,请考虑在所用的最通用的绑定中与在文档风格 SOAP 绑定中一样,涉及 XML 文档交换。此处,将部件值表示为文字的 XML 而不是 Java 对象将非常高效,当使用文档风格 SOAP 绑定进行调用时,可以不需要解析或序列化/反序列化。

修改绑定选择算法

绑定选择算法的修改非常直截了当。所有开发者必须做的是编写他们自己的 WSIFPortFactory 实现,或扩展现有的实现。请考虑 WSIFDynamicPortFactory。它存储动态提供者列表,该列表根据需要给特殊的 WSDL 绑定生成一个 WSIFPort。例如,这个端口工厂根据提供者类型查找动态提供者,这样它知道哪一个动态提供者处理 SOAP 端口,哪一个处理我们可能定义的 CORBA 端口,等等。我们可以用我们自己的 getPort() 方法扩展该端口工厂来选择需要的端口。为了说明这是有帮助的情况,请考虑清单 4 中的地址簿 Web 服务。

清单 4:地址簿 Web 服务


http://www.ibm.com/namespace/wsif/samples/ab"
xmlns:tns="
http://www.ibm.com/namespace/wsif/samples/ab"
xmlns:typens="
http://www.ibm.com/namespace/wsif/samples/ab/types"
xmlns:xsd="
http://www.w3.org/1999/XMLSchema"
xmlns:soap="
http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:java="
http://schemas.xmlsoap.org/wsdl/java/"
xmlns="
http://schemas.xmlsoap.org/wsdl/">















transport="
http://schemas.xmlsoap.org/soap/http"/>



namespace="
http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/"/>


namespace="
http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/"/>





namespace="
http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/"/>


namespace="
http://www.ibm.com/namespace/wsif/samples/ab"
encodingStyle="
http://schemas.xmlsoap.org/soap/encoding/"/>









http://localhost:8080/soap/servlet/rpcrouter"/>





该服务提供两种绑定:HTTP 之上的 SOAP 和本机 Java。在 WSDL 中直接绑定 Java 类没有标准的方法,但是这只会造成理解上的障碍,因此我们不再赘述。给定该服务多绑定的可用性,客户机将希望使用可能提供最好性能(比如 Java 绑定)的一个,大概因为它包含抽象操作到 Java 方法调用直接转换,而不需要网络、序列化/反序列化等操作。当然,Java 绑定只在部署了服务的环境可用。不象 SOAP 绑定,它不能在因特网上公用。因此我们希望做的是当可以时选择 Java 绑定,而在其它情况下使用 SOAP 绑定。如清单 5 所示,可以通过编写我们自己的 WSIFPortFactory 来实现。

清单 5:定制的绑定选择算法(请参阅参考资料以获取全部代码)

public class MyWSIFPortFactory extends
WSIFDynamicPortFactory {
public WSIFPort getPort () throws WSIFException {
WSIFException ex = null;
WSIFPort portInstance = null;
// examine list of available ports
// do we have a port with a Java binding?
for(int i = 0; i < myPortsArr.length; ++i) {
try {
Port port = myPortsArr[i];
Binding binding = port.getBinding();
if (binding instanceof JavaBinding) {
// attempt to create a port that can
// make invocations using this binding
portInstance =
createDynamicWSIFPort(def, service, port);
if(portInstance != null) {
return portInstance;
}
}
} catch(WSIFException wex) {
if(ex == null) {
ex = wex;
}
}
}
// unable to create a port that can invoke a Java
// binding (why? perhaps there is no Java port
// for this service, or the Java port cannot be
// created for invocation since we are not in
// an environment that has access to the resources
// that the Java binding uses)
// use WSDL ports with other
// bindings for invoking the service
// Full code not shown here due to length.
// Please see the Resources section at the end of
// this article to download the actual code.
}
}

如果您下载了清单 5 中示例的全部代码(参考资料部分中可得到),您应该仔细查看下面的指导说明来执行它:

将 zip 压缩文档解压缩到某个目录(本例我们使用 C:\Forge)。它将创建一个子目录,比如 C:\Forget\wsif-1.0-my-factory。
当您准备好编译这个示例时,务必包括 WSIF 文档中描述的所有必需的 JAR 文件。
编译 C:\FORGE\wsif-1.0-my-factory\samples 中的样本源代码,然后将包含已编译的 Java .class 文件的这个目录添加到 CLASSPATH 环境变量中。

当它完全编译成功时,在命令行运行清单 6 中的第一个命令。它使用本地示例文件,并且利用修改的动态调用器。

清单 6:本地应用程序中的动态调用

C:\jdk1.3\bin\java.exe -classpath ".;C:\Forge\wsif-1.0-my-factory\samples;
C:\Forge\wsif-1.0\samples;C:\Forge\wsif-1.0\samples\generated;
C:\Forge\wsif-1.0\samples\generated;C:\Forge\xml-soap\xml_soap22.jar;C:\Forge
\jaxp-1.1\jaxp.jar;C:\Forge\jaxp-1.1\crimson.jar;C:\Forge\javamail-1.2\mail.jar;
C:\Forge\jaf-1.0.1\activation.jar;C:\Forge\wsif-1.0\lib\wsif-all-1.0.jar"
clients.MyDynamicInvoker samples\services\stockquote\Stockquote.wsdl
getQuote IBM
Reading WSDL document from 'samples\services\stockquote\Stockquote.wsdl'
Preparing WSIF dynamic invocation
DEBUG: examining for selection port SOAPPort
DEBUG: selected soap port SOAPPort
DEBUG: examining for selection port JavaPort
DEBUG: selected java port JavaPort
Preffered port name 'JavaPort'
Executing operation getQuote
Result:
quote=90.05
Done!

清单 7 展示了第二个使用 WSDL 的示例,来自 Web 服务站点 Xmethods.net 而不是本地示例文件。

清单 7:跨网络的动态调用

C:\jdk1.3\bin\java.exe -classpath ".;C:\Forge\wsif-1.0-my-factory\samples;
C:\Forge\wsif-1.0\samples;C:\Forge\wsif-1.0\samples\generated;
C:\Forge\wsif-1.0\samples\generated;C:\Forge\xml-soap\xml_soap22.jar;
C:\Forge\jaxp-1.1\jaxp.jar;C:\Forge\jaxp-1.1\crimson.jar;
C:\Forge\javamail-1.2\mail.jar;C:\Forge\jaf-1.0.1\activation.jar;
C:\Forge\wsif-1.0\lib\wsif-all-1.0.jar" clients.MyDynamicInvoker
http://services.xmethods.net/soap/urn:xmethods-
delayed-quotes.wsdl getQuote IBM
Reading WSDL document from 'http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl'
Preparing WSIF dynamic invocation
DEBUG: examining for selection port net.xmethods.services.stockquote.StockQuotePort
DEBUG: selected soap port net.xmethods.services.stockquote.StockQuotePort
Preffered port name 'net.xmethods.services.stockquote.StockQuotePort'
Executing operation getQuote
Result:
Result=90.0
Done!

在运行时更新/添加绑定实现

假如我们想要升级 SOAP 实现。使用该体系结构,我们可以不必重编译用户代码或存根代码完成到新的实现的迁移,因为 WSIF API 将保持不变。我们将编写新的 WSIFPort 实现,能够使用由新的 SOAP 实现提供的修改过的 SOAP 客户机 API 进行调用。接着,我们编写将 WSDL SOAP 接口转换到新的 WSIFPort 实现的动态提供者。一旦我们注册了这个新的动态提供者,它将代替以前注册的 SOAP 动态提供者,并且将通过新的 WSIFPort 实现进行所有 WSDL SOAP 端口调用。

请考虑一下我们定义我们自己的 WSDL 绑定的情况。首先,我们必须确保 WSIF 运行时能够装入带有新的绑定的 WSDL 文档;这需要我们为可扩展性元素定义处理程序,这些元素是使用 WSDL4J(请参阅参考资料)的扩展注册中心 API 添加到我们的 WSDL 中的元素。我们将不深入到这怎样实现的细节中。然后我们可以编写 WSIFPort 和动态提供者实现,以更新 SOAP 绑定同样的方式向端口工厂注册新的动态提供者。

存根体系结构

我们可以从这种体系结构得到的最重要的好处是:它使我们能够得到可由受管环境定制的客户机存根。所有 WSIF 存根扩展清单 8 指定的基本类。

清单 8:WSIFStub 基本类

// some methods and other details omitted
public abstract class WSIFStub {
/**
* Locates a port factory using JNDI if available,
* otherwise uses dynamic port factory with
* pre-registered dynamic providers
*/
protected void locatePortFactory(.....) {
.....
}
/**
* Initializes stub with ports defined in WSDL document
* document must contain *exactly* one service and all
* ports must implement one and only one port type.
*/
protected void initializeFromLocation (...) {
.....
}
/**
* Return the port currently being used.
*/
public WSIFPort getPort () {
return wp;
}
/**
* Return the port factory currently being used.
*/
public WSIFPortFactory getPortFactory () {
return wpf;
}
/**
* Create a new proxy using the given WSIFPortFactory.
*/
public void setPortFactory (WSIFPortFactory wpf) {
.....
}
/**
* Create a new proxy pre-configured to use the given port
* for interacting with the service.
*/
public void setPort (WSIFPort wp) {
.....
}
/**
* Select the port to use by giving the name of the port
* that is desired. If a port of that name cannot be retrived from
* the port factory than an exception will be thrown. The port
* I use will only be updated if this method is successful.
*/
public void selectPort (String portName) {
.....
}
}

这种体系结构给了我们巨大的好处。在允许受管环境顺着模式作出改变的同时,它使应用程序能够使用同一存根,而不必重新编译任何东西。请考虑清单 5 中的例子,我们使用定制的绑定选择算法编写了我们自己的端口工厂。如果我们在应用程序服务器环境操作 JNDI,我们可以将该端口工厂实现绑定到恰当的指定的 JNDI 环境。当存根在初始化期间查找端口工厂时,它将得到新的实现。当然,我们可以通过直接调用存根上的 setPortFactory 方法强制在存根所使用的端口工厂进行改变(如果这是我们想要做的),或者我们可以通过使用存根的 setPort 方法强制使用特殊端口。

总结

随着 Web 服务持续发展,使用 SOAP 之外的协议访问服务端点将变得很普遍。因此当我们编写使用 Web 服务的应用程序时,我们需要工作在 WSDL 级而不是在 SOAP 级的 API。

WSIF 提供了着眼于 Web 服务调用的抽象方式,这样我们可以使用不受绑定束缚的调用 API 编写应用程序。WSIF 有生成可定制存根的端口类型编译器;WSIF API 足够简单,以至于应用程序能够通过直接使用它来进行无存根调用。WSIF 的体系结构能够以灵活的方式定义定制端口和端口工厂,并且也使被创建的消息能够使用任何本机类型系统。在存根用来进行调用的端口或端口工厂中,对于受管环境(比如应用程序服务器),生成的存根有入口点来进行运行时修改。

Web 服务需要独立于绑定的可扩展调用框架,WSIF 是朝该方向迈出的第一步。

参考资料

  • 请参加关于这篇文章的讨论论坛
  • 请阅读介绍性文章,它讨论了 WSIF 怎样促成当前 Web 服务调用模型的改进,并且描述了 WSIF 的一些主要功能。
  • 您可以从此处下载本文清单 5 的所有代码以及清单 6 和清单 7 中的示例。
  • 请下载 alphaWorks 上的 WSIF 分发包,并且试验比较简单的样本。它将给您一个由 WSIF 支持的不同调用风格的第一手示例以及它优于特定协议客户机 API 的优势。
  • 重温 WSDL 规范,看一看允许哪一种扩展;您也可以学习怎样使用 WSDL 扩展机制定义用来访问 Web 服务的 SOAP 绑定。
  • 重温 SOAP 规范本身。
  • 如果以前您没有对 Web 服务编过程,Web Services Toolkit 是很好的起点。
  • 请查看 WSDL4J,一个可扩展的 WSDL 分析框架,WSIF 在此基础上进行构建。

关于作者

Nirmal K. Mukhi 是 IBM 的 T J Watson Research Lab 的“副研究员”,自 2000 年 11 月,他一直在从事各种 Web 服务技术的研究。他还对 AI、创造性编写以及过时的计算机游戏感兴趣。您可以通过
nmukhi@us.ibm.com 与 Nirmal 联系。


Aleksander Slominski 是 Indiana University 的博士生,他是 IU Extreme! Lab 的研究助理,致力于实现“公共组件体系结构”的 XML/SOAP 启用版。他还设计和实现了“XML 拖解析器”(XML Pull Parser),并且对 XML 的性能和可用性方面感兴趣。在 2001 年夏天期间,他是 IBM 的 T J Watson Research Lab 的实习生,在那里他从事 WSIF 第一版的研究。您能够通过 aslom@indiana.edu 和 Alek 联系。

浏览:无SOAP的Web服务,第一部分

关键词:
相关文章
分享到:
2010-2012 北京深蓝海域信息科技有限公司
Darkblue Sea Software Co., Ltd. all rights reserved
京ICP备13004508号-1
地址:北京市昌平区北清路1号珠江摩尔国际中心6号楼1单元907单位
电话:010-89146616/82969378
传真:010-82969378
公司介绍 | 人才招募 | 网站地图 | 联系我们 | 企业资质