这是我自己翻译的,效果不怎么样?如果不满意,请查看原文:Testing SOAP Headers with a Simple Axis Handler


这不一教学示例,但是可以共享我学习中使用简单Axis Handler(有点类似于ASP.NET soap扩展).我写2个程序——一个基于java控制台程序样式的简单Web service客户端和一个Web service。在这个客户端中调用Web service的方法Test(),调用同时添加了一个包含一个用户名和密码的SOAP header。这个Web service拥有一个简单的Handler,在部署描述符中定义为一个request Handler, 检查每个请求并且保证用户名和密码正确地存在于SOAP header中。当Web service方法获得它的时候,这个Handler也设置有效用户名在ThreadLocal variable中。如果请求没有包含正确的SOAP header,用户名及密码,那么将不能够连接Web service。

Handler类可以通过几种方式设置数据并被Web service的方法获取,其中我知道的一种方法是使用ThreadLocals,虽然它备受争议,但是我认为它可能在这种特殊情况里有用。

我使用的Axis版本是使1.3,我不认为您也是使用这个版本。注意这是测试码,不为产品测试。如果您在代码里发现某些事情有错误,我非常希望您能告诉我。另外要注意的是我建立SOAP header和使用XML namespace的方式有点草率。我知道它可以做得更好,但是我的目的是测试那些handler代码:)

注意到这些Web服务的客户端代码是从WSDL自动生成,所以我并不担心怎么在这里贴出代码。

First, the client code:

package test;

import org.apache.axis.message.*;

public class MyClient {

 
public static void main(String[] args) {
  
  System.out.println(
"Hello, this is the client!");
  
  MyServiceServiceLocator wsloc 
= new MyServiceServiceLocator();
  
  SOAPHeaderElement oHeaderElement; 
  javax.xml.soap.SOAPElement oElement;
  MyServiceSoapBindingStub ws;
  
   
try {
    ws 
= (MyServiceSoapBindingStub)wsloc.getMyService();

    oHeaderElement 
= new SOAPHeaderElement("http://test",
     
"securityHeader");
    oHeaderElement.setPrefix(
"sec"); 
    oHeaderElement.setMustUnderstand(
false);
    oElement 
= oHeaderElement.addChildElement("username"); 
    oElement.addTextNode(
"johan"); 
    oElement 
= oHeaderElement.addChildElement("password"); 
    oElement.addTextNode(
"secret"); 
      
    ws.setHeader(oHeaderElement);
    System.out.println(ws.test());
   }
 catch (Exception e) {
    
// TODO Auto-generated catch block
    e.printStackTrace();
   }
  
 }

}


Then, the web service code (most comments and javadoc removed):

package test.service;

import test.service.handler.MyHandler;

public class MyService 
{
 
public String test()
 
{
  String username 
= MyHandler.getUsername();
  MyHandler.setUsername(
null); //clean up
  
  
return "Hello from Service! User is = " + username;
 }

}

Finally, the Handler code looks something like this:

package test.service.handler;

import org.apache.axis.AxisFault;
import org.apache.axis.Message;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;

import java.util.Iterator;

import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;

import org.apache.axis.message.SOAPEnvelope;

/**
 * Simple Axis handler which looks for a SOAP header
 * containing two elements - username and password. Invoke() method 
 * checks these
 * 
 * 
@author Johan Danforth
 
*/

public class MyHandler extends BasicHandler {

 
private static final long serialVersionUID = 1L;
 
private static ThreadLocal _username = new ThreadLocal();

    
public static String getUsername() {
        
return ((String) (_username.get())).toString();
    }

    
    
public static void setUsername(String value) {
        _username.set(value);
    }

 
 
/**
  * Method called by Axis handler, checks SOAP header with 
  * username and password.
  * 
  * 
@throws AxisFault if header is missing or invalid or wrong username or password
  
*/

 
public void invoke(MessageContext msgContext) throws AxisFault {

  
boolean processedHeader = false;
  
  
try {
   Message msg 
= msgContext.getRequestMessage();
   SOAPEnvelope envelope 
= msg.getSOAPEnvelope();
   SOAPHeader header 
= envelope.getHeader();
   Iterator it 
= header.examineAllHeaderElements();
   SOAPHeaderElement hel;
   
   
while (it.hasNext()) {
    hel 
= (SOAPHeaderElement) it.next();
    String headerName 
= hel.getNodeName();
    
if(headerName.equals("sec:securityHeader"))
    
{
     checkUsername(hel);
     processedHeader 
= true;
    }

   }

  }
 catch (SOAPException e) {
   
//capture and wrap any exception. 
   throw new AxisFault("Failed to retrieve the SOAP Header or it's details properly.", e);
  }


  
if(!processedHeader)
   
throw new AxisFault("Failed to retrieve the SOAP Header");
  
 }


 
private void checkUsername(SOAPHeaderElement hel) throws AxisFault {
  String username 
= getUsername(hel);
  String password 
= getPassword(hel);
  
  
if(!(username.equals("johan"&& password.equals("secret")))
  
{
   
throw new AxisFault("Access Denied");
  }

  
else
  
{
   
//set username as threadlocal variable
   _username.set(username);
  }

 }


 
private String getPassword(SOAPHeaderElement hel) throws AxisFault {
  org.w3c.dom.Node passwordNode 
= hel.getLastChild();
  String nodename 
= passwordNode.getNodeName(); 
  
if(!nodename.equals("sec:password"))
   
throw new AxisFault("Missing password element in SOAP header.");
  String password 
= passwordNode.getFirstChild().getNodeValue();
  System.out.println(
"password = " + password);
  
return password;
 }


 
private String getUsername(SOAPHeaderElement hel) throws AxisFault {
  org.w3c.dom.Node usernameNode 
= hel.getFirstChild();
  String nodename 
= usernameNode.getNodeName(); 
  
if(!nodename.equals("sec:username"))
   
throw new AxisFault("Missing username element in SOAP header.");
  String username 
= usernameNode.getFirstChild().getNodeValue();
  System.out.println(
"username = " + username);
  
return username;
 }

}

我必须贴出部署描述和Web.xml的内容。我在同一个Web应用程序中运行Axis Servlets。它有助于您在实际情况中使用您更喜欢的方式。我认为当我使用Eclipse的最新的版本时,这种方法更容易使用。在web.xml中充满Axis资源的原因是我使用单独的server-config.wsdd来代替通过Axis管理工具注册服务来指示一个单独的deploy.wsdd文件。我也附上一个deploy.wsdd文件示例,以防万一有人不熟悉服务器配置文件。

My web.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 
<display-name>
 HelloWorld2
</display-name>
 
<servlet>
  
<display-name>
  Apache-Axis Servlet
</display-name>
  
<servlet-name>AxisServlet</servlet-name>
  
<servlet-class>
  org.apache.axis.transport.http.AxisServlet
</servlet-class>
 
</servlet>
 
<servlet>
  
<display-name>
  Axis Admin Servlet
</display-name>
  
<servlet-name>AdminServlet</servlet-name>
  
<servlet-class>
  org.apache.axis.transport.http.AdminServlet
</servlet-class>
  
<load-on-startup>100</load-on-startup>
 
</servlet>
 
<servlet-mapping>
  
<servlet-name>AxisServlet</servlet-name>
  
<url-pattern>/servlet/AxisServlet</url-pattern>
 
</servlet-mapping>
 
<servlet-mapping>
  
<servlet-name>AxisServlet</servlet-name>
  
<url-pattern>*.jws</url-pattern>
 
</servlet-mapping>
 
<servlet-mapping>
  
<servlet-name>AxisServlet</servlet-name>
  
<url-pattern>/services/*</url-pattern>
 
</servlet-mapping>
 
<servlet-mapping>
  
<servlet-name>AdminServlet</servlet-name>
  
<url-pattern>/servlet/AdminServlet</url-pattern>
 
</servlet-mapping>
 
<welcome-file-list>
  
<welcome-file>index.html</welcome-file>
  
<welcome-file>index.htm</welcome-file>
  
<welcome-file>index.jsp</welcome-file>
  
<welcome-file>default.html</welcome-file>
  
<welcome-file>default.htm</welcome-file>
  
<welcome-file>default.jsp</welcome-file>
 
</welcome-file-list>
</web-app>

My server-config.wsdd looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 
<globalConfiguration>
  
<parameter name="sendMultiRefs" value="true"/>
  
<parameter name="disablePrettyXML" value="true"/>
  
<parameter name="adminPassword" value="admin"/>
  
<parameter name="attachments.Directory" value="C:\Java\eclipse\workspace\HelloWorld2\.deployables\HelloWorld2\WEB-INF\attachments"/>
  
<parameter name="dotNetSoapEncFix" value="true"/>
  
<parameter name="enableNamespacePrefixOptimization" value="true"/>
  
<parameter name="sendXMLDeclaration" value="true"/>
  
<parameter name="sendXsiTypes" value="true"/>
  
<parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
  
<requestFlow>
   
<handler type="java:org.apache.axis.handlers.JWSHandler">
    
<parameter name="scope" value="session"/>
   
</handler>
   
<handler type="java:org.apache.axis.handlers.JWSHandler">
    
<parameter name="scope" value="request"/>
    
<parameter name="extension" value=".jwr"/>
   
</handler>
  
</requestFlow>
 
</globalConfiguration>
 
<handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
 
<handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
 
<handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
 
<service name="AdminService" provider="java:MSG">
  
<parameter name="allowedMethods" value="AdminService"/>
  
<parameter name="enableRemoteAdmin" value="true"/>
  
<parameter name="className" value="org.apache.axis.utils.Admin"/>
  
<namespace>http://xml.apache.org/axis/wsdd/</namespace>
 
</service>
 
<service name="Version" provider="java:RPC">
  
<parameter name="allowedMethods" value="getVersion"/>
  
<parameter name="className" value="org.apache.axis.Version"/>
 
</service>
 
<service name="MyService" provider="java:RPC" style="wrapped" use="literal">
  
<operation name="test" qname="ns3:test" returnQName="ns3:testReturn" returnType="xsd:string" soapAction="" xmlns:ns3="http://test" xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
  
<parameter name="allowedMethods" value="test"/>
  
<requestFlow>
   
<handler type="java:test.service.handler.MyHandler">
    
</handler>
  
</requestFlow>
  
<parameter name="typeMappingVersion" value="1.2"/>
  
<parameter name="wsdlPortType" value="MyService"/>
  
<parameter name="className" value="test.service.MyService"/>
  
<parameter name="wsdlServicePort" value="MyService"/>
  
<parameter name="schemaQualified" value="http://test"/>
  
<parameter name="wsdlTargetNamespace" value="http://test"/>
  
<parameter name="wsdlServiceElement" value="MyServiceService"/>
 
</service>
 
<transport name="http">
  
<requestFlow>
   
<handler type="URLMapper"/>
   
<handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
  
</requestFlow>
  
<parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/>
  
<parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
  
<parameter name="qs.list" value="org.apache.axis.transport.http.QSListHandler"/>
  
<parameter name="qs.method" value="org.apache.axis.transport.http.QSMethodHandler"/>
  
<parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/>
  
<parameter name="qs.wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
 
</transport>
 
<transport name="local">
  
<responseFlow>
   
<handler type="LocalResponder"/>
  
</responseFlow>
 
</transport>
</deployment>

A sample deploy.wsdd could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Use this file to deploy some handlers/chains and services      -->
<!-- Two ways to do this:                                           -->
<!--   java org.apache.axis.client.AdminClient deploy.wsdd          -->
<!--      after the axis server is running                          -->
<!-- or                                                             -->
<!--   java org.apache.axis.utils.Admin client|server deploy.wsdd   -->
<!--      from the same directory that the Axis engine runs         -->
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  
<service name="MyService" provider="java:RPC" style="wrapped" use="literal">
      
<parameter name="wsdlTargetNamespace" value="http://test"/>
      
<parameter name="wsdlServiceElement" value="MyServiceService"/>
      
<parameter name="schemaQualified" value="http://test"/>
      
<parameter name="wsdlServicePort" value="MyService"/>
      
<parameter name="className" value="test.service.MyService"/>
      
<parameter name="wsdlPortType" value="MyService"/>
      
<parameter name="typeMappingVersion" value="1.2"/>
      
<operation xmlns:operNS="http://test" xmlns:retNS="http://test" xmlns:rtns="http://www.w3.org/2001/XMLSchema" name="test" qname="operNS:test" returnQName="retNS:testReturn" returnType="rtns:string" soapAction="">
      
</operation>
      
<parameter name="allowedMethods" value="test"/>
  
<requestFlow>
   
<handler type="java:test.service.handler.MyHandler">
    
</handler>
  
</requestFlow>
  
</service>
</deployment>
posted on 2007-10-22 21:04  逐风者  阅读(3347)  评论(0编辑  收藏  举报