了解如何通过使用 SOAP 消息处理程序来读取和缓存 SOAP 主体,从而为 SOAP/HTTP Web服务编写可靠的客户机。这种方法在出现服务器故障或网络服务故障等情况下保存准备 Web 服务调用所使用的数据。客户机从 Web 服务获得响应后,可以将此数据从缓存丢弃,否则将使用相同的数据再次调用 Web 服务。
引言
在通常的 Web 服务调用场景中,Web 服务客户机准备调用,并随后调用 Web 服务。如果出现临时系统错误、网络故障或服务不可用,准备调用过程中使用的数据将丢失。可以采用多种方式来保存此数据。一种方法是使用 SOAP 消息处理程序(以下简称处理程序);不过处理程序最常用于进行 SOAP Header 处理。SOAP Header 用于承载请求的上下文数据,例如安全性和事务性之类的服务质量(Quality of Service,QoS)请求。在这些情况下,可以使用处理程序来读取 SOAP 主体。本文将说明如何使用处理程序来缓存主体、如何在出现故障时使用此缓存以及如何编写可靠的 Web 服务客户机。
编写 Web 服务消息处理程序
开发消息处理程序的主要目的是保存准备调用 Web 服务时使用的数据。清单 1 显示了一个消息处理程序,用于在发送请求时读取请求主体。
清单 1. 消息处理程序代码
package com.ibm.reliablewsclient.ws;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.GenericHandler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.MessageContext;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPMessage;
/*
* Created on Aug 3, 2006 @author Shailesh K Mishra (shailekm@in.ibm.com)
*
*/
public class ClientHandler extends GenericHandler {
private Logger logger;
public static SOAPBody body_of_request=null;
/**
*
*/
public ClientHandler() {
super();
// TODO Auto-generated constructor stub
}
/*
* (non-Javadoc)
*
* @see javax.xml.rpc.handler.Handler#init(javax.xml.rpc.handler.HandlerInfo)
*/
public void init(HandlerInfo arg0) {
// set up logger
logger = Logger.getLogger("com.ibm.reliablewsclient.ws");
super.init(arg0);
}
/*
* (non-Javadoc)
*
* @see javax.xml.rpc.handler.Handler#getHeaders()
*/
public QName[] getHeaders() {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see javax.xml.rpc.handler.Handler#handleRequest(javax.xml.rpc.handler.MessageContext)
*/
public boolean handleRequest(MessageContext arg0) {
try {
logger.info("Begin procession ClientHandler.handleRequest");
//generate SOAP body
SOAPMessage message = ((SOAPMessageContext) arg0).getMessage();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
SOAPBody body = envelope.getBody();
body_of_request=body;
logger.info("Request Body : " + body.toString());
logger.info("Completed procesing for ClientHandler.handleRequest");
} catch (Throwable ex) {
throw new JAXRPCException("Error in handleRequest", ex);
}
return true;
}
/*
* (non-Javadoc)
*
* @see javax.xml.rpc.handler.Handler#handleResponse(javax.xml.rpc.handler.MessageContext)
*/
public boolean handleResponse(MessageContext arg0) {
return true;
}
}
清单 1 中的处理程序代码将读取消息主体,并将其赋值给静态变量。此静态 body_of_request 字段用于缓存在准备 Web 服务调用时使用的数据。这是非常简单的缓存技术,但不能扩展。
编写可靠的托管 Web 服务客户机
托管客户机 是在托管环境中运行的客户机,即它通过应用服务器进行工作。我将说明如何通过使用 Servlet 作为客户机来编写可靠的托管客户机。首先,您需要编写 Web 服务,并随后为该 Web 服务生成存根。要生成存根,请在开发环境(我使用的是 IBM Rational ® Application Developer™)中右键单击 Web 服务的 WSDL 文件,然后单击生成客户机选项。生成存根后,就可以编写 Servlet 了。清单 2 显示了 Servlet 的 doGet 方法。
清单 2. Servlet 的 doGet 方法
try {
DemoWSProxy proxy=new DemoWSProxy();
String str=proxy.generateId("John",2834742,"IBM Bangalore");
throw new RemoteException("To demostrate");
} catch (RemoteException e) {
try {
SOAPConnectionFactory fact;
fact = SOAPConnectionFactory.newInstance();
SOAPConnection con = fact.createConnection();
javax.xml.soap.SOAPFactory sf = SOAPFactory.newInstance();
MessageFactory mfact = MessageFactory.newInstance();
SOAPMessage smsg = mfact.createMessage();
SOAPPart prt = smsg.getSOAPPart();
SOAPEnvelope env = prt.getEnvelope();
env.addChildElement(ClientHandler.body_of_request);
//Set the WebService end point URL
URL endpoint = new URL("http://localhost:9080/
ReliableWSClientProject/services/DemoWS");
//Send the message
SOAPMessage response = con.call(smsg, endpoint);
System.out.println(response.getSOAPBody().toString());
response.writeTo(arg1.getOutputStream());
System.out.println();
//Close the connection
con.close();
} catch (UnsupportedOperationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (SOAPException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
调用 doGet 方法时,它将实例化 WSProxy 类(在存根生成期间创建),并调用 Web 服务的 generateId 方法。出于演示目的,我引发了一个 RemoteException 异常来表明使用的是缓存数据。调用 Web 服务时,消息处理程序将读取请求的主体,并将整个主体保存在 body_of_request 静态变量中。现在,当执行到 throw RemoteException 处时,将引发远程异常,流将进入 catch 块。在此 catch 块中,将使用所保存的请求主体来准备 SOAP 请求,以便再次调用 Web 服务。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
SAP收购CallidusCloud 与Salesforce竞争
一直被称为后台办公巨头的SAP现在似乎也想在前台办公大展拳脚。 最新的迹象是SAP收购CallidusClou […]
-
API设计如龙生九子 各不相同
IT咨询管理公司CA Technologies对API产业做了个问卷调查,问卷内容涉及API设计风格以及管理部署的新动向。调查结果表明,JSON与XML可谓两分天下。
-
API设计:如何正确开发应用程序接口
在交互组件化软件的世界里,没有比让组件之间以及组件与移动设备和浏览器之间进行连接的应用程序接口(API)更重要的东西了。
-
从头开始实现领域驱动设计
领域描述业务;它是驱动企业的概念和逻辑的集合。如果遵循领域驱动设计(DDD)这一本质,那么领域就是应用程序中最重要的组成部分。