中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > Java与XML
Sending Out-of-Band Messages to SOAP-Based Web Services @ JDJ
作者:未知 时间:2005-08-10 18:49 出处:Java频道 责编:chinaitpower
              摘要:Sending Out-of-Band Messages to SOAP-Based Web Services @ JDJ

SOAP, the Simple Object Access Protocol, is a lightweight toolkit for building Web services. It is an amalgam of ubiquitous technologies - HTTP and XML. Though the likes of Microsoft, IBM, and the Apache Software Foundation normally have little in common, all support it as a foundation for deploying Web services. One of the great advantages of SOAP's lightweight nature is the simplicity of server-side programming. A SOAP service needs no knowledge of the SOAP environment. In fact, just about any Java class that exposes public methods can be turned into a SOAP service.

Unfortunately, sophistication usually brings complication. While there is little you need to do to write a SOAP-based Web service, it is difficult for a service to know much about the context of a request being made. Should the service evolve over time, you might want the client to provide a service version so a proper response may be sent to a back-revision client. If a service is available to a number of applications, it may be useful to know which is making a request. The obvious approach to solving this problem is to add additional parameters for these things to the service. This quickly becomes annoying for the service programmer, as every method in every service would require these parameters. Things become tedious for the client programmer also, as such information is relatively static and would be duplicated across every call.

A Basic SOAP Web Service
Consider Listing 1 (all code listings may be found at  . www.sys-con.com/webservices/sourcec.cfm). TestService certainly is a trivial service, but no special coding is required to make this a SOAP service. The SOAP RPC router and Java reflection do the work of receiving a request and matching it up with a deployment descriptor and method signature. The code to call it would look like Listing 2. You will need a copy of SOAP from Apache to try the examples. These were built with version 2.0. Use the SOAP administrative interface to deploy the service.

The obvious way to add information like application name and service version to this example would be to add parameters to the call. A better approach would be to develop an out-of-band communication channel with SOAP services. Likewise, the service would need some way of finding these values while servicing a request. As HTTP is one of the component technologies, can the additional information be included in HTTP headers?

HTTP and SOAP
Looking at the conversation between the example client and server above, we see the conversation shown in Listing 3. With the exception that the content of the POST is a SOAP payload, there is nothing unusual about this interaction. So, if we are to use HTTP headers to transmit out-of-band messages, how can we affect the SOAP conversation to include additional headers? It might be tempting to use the SOAPAction value, but its definition is somewhat fuzzy and probably should be avoided. The mechanism we should use is not obvious from the client example above, but there is a way.

Extending the SOAPHTTPConnection
There is a method on the Call object that enables us to provide an instance of a SOAPTransport. SOAPTransport is responsible for transmitting the SOAP payload to the server and receiving the response. Normally, this would be an instance of SOAPHTTP Connection, though you could use an SMTP-based transport. Looking at the documentation for SOAPTransport, we see that the send() method enables us to contribute headers to the request. There is also a getHeaders() method that enables us to see the headers from the response. Our solution lies in extending SOAPHTTPConnection and providing our own send(), as in Listing 4.

Our send() arranges for the out-of-band messages to be included with any headers SOAP has inserted, then calls super.send(). The messages are stored in a static hash table, so they will be shared across every instance of this SOAPTransport. We have also included some helper methods to add, remove, and get messages from the hash table. To use this new SOAPTransport we modify TestMain as in Listing 5.

The static initial-ization block will ensure that any mes-sages are set on our SOAPTra-nsport before we have a chance to use it. If TestMain was a servlet, the APP_NAME and APP_VER values might be obtained from the servlet conf-iguration and set dur-ing the servlet's init(). Running the modified sample, the message sent from the client now looks like Listing 6.

Creating a Service Context for SOAP Services
The headers are now included in the request being sent to the server, and the server is accepting them, though not acting upon them. On the receiving end, the challenge is the fact that the SOAP service is running in a context-free environment. If we can solve our problem without building a dependency upon SOAP mechanisms into our services, we will be able to use our services in other environments. Listing 7 shows a class that provides the necessary context.

Note the use of an InheritableThreadLocal to store a hash table. Values stored with a ThreadLocal's get() and set() methods are unique to that thread. An Inheritable ThreadLocal ensures that any threads created after a value is set inherit that value. This is important since, server-side, the request is driven by a servlet called RPCRouterServlet. Most servlet containers, such as Tomcat or JRun, will create a pool of threads to service requests. Each time we make a request, a thread is taken from the pool and returned when the request is complete. Our service may be called by any number of applications (and versions of applications) and, using an InheritableThreadLocal, the application name and version may be attached to the thread servicing the request.

Next, we must extend the SOAP RPCRouterServlet as in Listing 8. This extension intercepts the call to doPost() (RPCRouterServlet rejects GET requests), extracts the messages, and adds them to the ServiceContext. Following the call to super.doPost(), it calls ServiceContext.clear() to ensure that the thread does not service another request with incorrect information attached to it. The final step, Listing 9, updates the service to use the ServiceContext. Now, running the TestMain class:

> java TestMain foo

The returned value was 'The argument you sent was 'foo', your application name is 'TestMain', your application version is '1.0'"

Cautions
The idea of using a ThreadLocal or InheritableThreadLocal client-side to transmit user credentials (i.e., value of Http ServletRequest.getRemoteUser()) might be tempting. Doing so asks the client of a service to identify itself honestly. Sending a username and password would be done in the clear. Unless you secure access to your services to trusted clients or have trusted clients digitally sign the message, it probably isn't a good idea.

If you look at SOAPSMTPConnection you'll see that, although it does implement the SOAPTransport interface, it ignores the headers parameter on the send() method. This technique will not work with an unmodified Apache SOAP implementation if you are using SMTP as a transport.

Summary
Using HTTP headers as an out-of-band communication channel is relatively straight-forward, and the channel can just as easily be extended to be bi-directional. Use of this technique should take some unnecessary drudgery out of SOAP programming.

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有