内容


使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 2 部分

实现接收模式

系列内容:

此内容是该系列 # 部分中的第 # 部分: 使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 2 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 2 部分

敬请期待该系列的后续内容。

引言

第 1 部分中,我们讨论了如何将请求-响应和单向模式应用于 Web 服务端点。在这第 2 部分中,您将了解到如何将其他两种模式(要求-响应和通知)应用于 Web 服务客户端(调用端)端点。让我们考虑这样一个应用程序集成场景示例:假定有一个应用程序,比如旅行预订应用程序 ("App1"),该应用程序包括各种组件。作为我们讨论的参照点,该应用程序接受来自客户的输入,例如旅行的出发地、目的地和信用卡信息。然后,该应用程序通过与其他应用程序(如信用验证系统 ("App2"))集成进行订票。此外,需要一个付款应用程序 ("App3")。App2 公开一个 Web 服务来验证信用卡,而 App3 通过从信用卡中扣除相应金额来处理付款。App1 公开两个 Web 服务;一个 Web 服务从 App3 接收消息(用于处理付款的确认请求)作为输入,接着发送确认(“继续”)消息,另一个 Web 服务从 App3 接收“付款已完成通知”消息。

在要求-响应模式中,端点是一个客户端,它将消息发送到预期返回响应的服务端点,并接收从该服务端点返回的相关消息。在我们的示例中,当 App3 准备好处理付款请求并且 App1 返回确认(“继续付款”)消息时,App3 调用 App1 公开的“付款请求确认”Web 服务。对于此处讨论的应用程序 App3,这是要求-响应操作。

在通知模式下,扮演将消息发送到服务端点的客户端的角色的端点并不期望从该服务端点返回响应。在本示例中,“通知付款完成”Web 服务由 App1 公开,而由 App3 在处理付款之后调用。对于 App3,这是通知操作。

在另一方面,对于 App2 的信用验证 Web 服务(App2 接受信用卡信息作为输入,以此对信用卡进行验证,并发送一条响应消息,告知该信用卡被批准或被拒绝),这是订票应用程序 App1 调用该服务时的请求-响应操作。类似地,对于付款应用程序 App3 公开的“付款”Web 服务,这是 App1 调用该服务时的单向操作,因为 App1 可以在发送该消息后继续执行一些其他任务。

从应用程序 App1 的角度来看,我们将基于要求-响应模式与外部应用程序 App3 的集成看作“同步服务”类型的活动,而将通知看作“异步接收”类型的活动。也就是说,在要求-响应和通知中,我们的参照点应用程序 App1 成为服务提供者(服务端点),并接收来自客户端的消息。

在本文中,您将了解如何在此类应用程序(假定基于 Java™)中实现这两种模式来接收 Web 服务。

Web 服务实现的开放源代码框架

Web 服务和客户端可以使用各种开放源代码框架实现。对于本文,我们将使用 Apache Axis 开放源代码框架来实现 Web 服务,同时还要结合使用 Java Architecture for XML Binding [sg3] (JAXB[I2]) 和 Java Message Service (JMS)。

应用程序客户端端点发出的请求

在此部分,您将了解如何在应用程序中为基于简单对象访问协议(Simple Object Access Protocol,SOAP)的 Web 服务操作实现同步服务和异步接收模式。对于此讨论,我们将假定使用 Document 样式的 Web 服务调用。如果外部客户端通过向应用程序发送消息来参与应用程序处理,同步服务和异步接收将尤为有用。

同步服务

对于同步服务的情况,应用程序充当服务实现端点,而外部参与者则是调用其公开的服务的客户端。同步服务的一个例子是外部监视系统。外部监视系统可以发送请求,以了解应用程序处理的状态,而应用程序可以提供状态信息。

如 Web 服务描述语言(Web Services Description Language,WSDL)语法所定义的,要求-响应操作包含输入和输出元素,首先输出,然后输入,如清单 1 中所示。

清单 1. 要求-响应操作的 WSDL
<wsdl:definitions .... >
    <wsdl:portType .... > *
        <wsdl:operation name="nmtoken" parameterOrder="nmtokens">
           <wsdl:output name="nmtoken"? message="qname"/>
           <wsdl:input name="nmtoken"? message="qname"/>
           <wsdl:fault name="nmtoken" message="qname"/>*
        </wsdl:operation>
    </wsdl:portType >
</wsdl:definitions>

在本例中,应用程序将针对每个应用程序要求公开一个 Web 服务 (SOAP)。服务需要从外部客户端接收输入参数,并将输出参数返回到它,同时在 WSDL 中对此进行定义。这些输出参数通常是一些有关应用程序状态的参数,从外部连接到应用程序的客户端需要从应用程序获取此状态。此 WSDL 将提供给希望调用此服务的客户端,以提供有关输入消息、输出消息和提供服务的 HTTP 端口或 JMS 端口的详细信息。此 Web 服务可以支持使用 SOAP over HTTP 或 JMS 作为传输协议。

应用程序可以使用 Apache Axis 服务器来实现这种异步服务类型的活动。Web 服务将在 Axis 服务器上运行一次(在应用程序安装期间)。服务实现类也是应用程序的一部分。

当外部客户端调用此服务时,Axis 服务器引擎将接收 SOAP 请求消息,并将在请求消息中接收到的参数作为 Element (org.w3c.dom.Element) 对象数组提供给服务实现类的方法。此方法必须对 Java 对象绑定使用 XML,因此实际对其使用的是 JAXB。通过使用 JAXB,将构造与输入 XML 元素对应的 Java 对象,并将其放入到 HashMap 中。然后将调用应用程序的 API 方法,并提供此 HashMap 作为输入。此 API 方法从应用程序获取调用方所需的信息,并构造一个 HashMap,将此信息作为输出参数对象放置到 HashMap 中。此 HashMap 将返回到服务实现方法。同时,应用程序将继续进行处理。为了更好地理解这一点,请参见清单 2 中给出的示例代码。

服务实现方法使用 JAXB 在 HashMap 中进行 Java 到 XML 的绑定,以便将其转换为 org.w3c.dom.Element 数组形式的 XML 元素。此 Element 数组是调用方的输出参数集,将返回到 Axis 服务器。接下来,Axis 服务器将使用这组输出参数 Elements 构造对 SOAP 消息的响应,并将响应消息发送回外部客户端。

清单 2. 作为 Web 服务公开的服务实现方法 GetActivityState
public Element[] getActivityState(Element[] inElements)
{
	Element[] retElements;
	String activityName = null;
	String requestOperation = null;
	
	if ((inElements[0].getChildNodes().getLength() == 1) && 
			inElements[0].getFirstChild().getNodeType() == Node.TEXT_NODE)
	{
		activityName = inElements[0].getFirstChild().getNodeValue();
	};
	
	if ((inElements[1].getChildNodes().getLength() == 1) && 
			inElements[1].getFirstChild().getNodeType() == Node.TEXT_NODE)
	{
		requestOperation = inElements[1].getFirstChild().getNodeValue();
	};
	
	ApplicationAPI appAPI  = ApplicationAPIFactory.getInstance().getApplicationAPI();
	if (requestOperation.equalsIgnoreCase("getActivityData"))
	{
		HashMap retData = appAPI.getDataFromActivity(activityName);
	}
	
	// use JAXB to convert each object value in the HashMap to 
	// its corresponding Element object. Populate the 
	// array of Element objects retElements with these Element objects.
	return retElements;
}

在前面的场景中,服务实现方法还可以查看输入 XML Element 数组,并确定需要调用应用程序中的哪个 API 方法(具体取决于外部客户端所请求的信息类型)。例如,即使支持不同类型的监视请求,一个具有唯一方法实现的类可以支持不同类型的请求。但在 Axis 服务器中可以部署多个服务,一个服务与一种请求类型对应,而所有这些服务以及输入和输出消息的详细信息可以在发布到外部客户端的一个 WSDL 中定义。

对于 JMS 传输的情况,应用程序可以使用 OpenJMS 服务器(JMS 实现)来处理 JMS 消息(其中包含 SOAP 消息作为内容)。将在 OpenJMS 服务器中为应用程序公开的每个 Web 服务打开单个队列,并为此队列创建一个消息侦听器(此操作将在应用程序启动时进行一次)。正如在前面的段落中所讨论的,如果应用程序公开多个服务,而仅有一个用于所有这些服务的服务实现方法和类,则每个队列的消息侦听器都将绑定到该应用程序公开的一个服务。在队列中接收到任何消息时,消息侦听器将调用 Axis 引擎,并在所绑定到的服务的引擎中设置了相应的服务名称(即与上面为 HTTP 服务定义的相同的服务名称)后将 SOAP 请求消息提供给它。然后,该引擎将调用此服务方法(即在前一段中描述的同一方法)。

异步接收

在本例中,应用程序将充当服务实现端点,而外部客户端将发送应用程序所使用的消息。没有响应发送回外部客户端。外部客户端将 SOAP 请求消息发送到 Web 服务后,并不等待任何响应。它将继续随后的处理。如果外部客户端需要控制某些应用程序处理,异步接收将特别有用。例如,外部客户端可以触发应用程序中的流程;它还可以使应用程序结束处理或停止,如清单 3 中所示。

如 WSDL 语法中所定义的,通知操作仅具有输出元素。

清单 3. 通知操作的 WSDL
<wsdl:definitions .... >
    <wsdl:portType .... > *
        <wsdl:operation name="nmtoken">
           <wsdl:output name="nmtoken"? message="qname"/>
        </wsdl:operation>
    </wsdl:portType >
</wsdl:definitions>

外部客户端可以通过 JMS 传输向 Web 服务发送 SOAP 请求;此请求为单向消息。Web 服务在 Axis 服务器上公开,将在应用程序启动期间在 OpenJMS 服务器上设置 JMS 接收队列。此模式的实现与同步服务部分所描述的涉及 JMS 的同步服务的实现一样,只是在调用应用程序的 API 方法后,服务实现方法并不从 API 方法接收任何输出参数(一个通知)。API 方法将按照从外部客户端接收的输入参数中请求的方式对应用程序状态执行相关操作。

结束语

在本文中,我们讨论了 Web 服务客户端端点的要求-响应模式和通知模式,并了解了如何使用与开放源代码框架有关的相应 Web 服务来支持将应用程序与基于这两种模式的客户端集成。

通过使用相应的框架(如 Axis、JAXB)和传输协议(如 HTTP 或 JMSWeb),可在单个 Java 应用程序的上下文中实现 Web 服务的四种服务端点模式。

您在本系列中学习的方法均来自我们在流程引擎的上下文中实现这四种 Web 服务模式的经验。我们希望和您分享在实现这些 Web 服务模式时所遇到的挑战,并向您提供我们所获得的解决方案。


相关主题

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=SOA and web services, Open source
ArticleID=156595
ArticleTitle=使用开放源代码框架的 Java 应用程序的 Web 服务集成模式,第 2 部分: 实现接收模式
publish-date=08282006