动态的为web service soap消息增加验证规则

在我们当前的 SaaS 系统中 requestresponse 的验证包括两部分,一部分为 jaxbschema 验证,一部分为局部业务规则约束的验证(通过在 service 实现中侵入代码进行验证)。

 

我一直觉得当前的验证(非数据库相关)不是很灵活,因此我就做了一个动态的验证框架,实现思路如下:

在我们的系统中每一个 service 对应多个 operation ,每一个 operation 既是一个 request/response 处理者。我们的验证是针对 request/response ,因此需要建表结构(示意)如下:

Vaidations

OperationID

操作 id

Type

类型 request/response

ValidateKey

验证的 key ,即 request/responsexpath 路径

ValidateRule

匹配 validateKey 的值 de 验证规则,利用正则表达式

所有的验证规则都会进行缓存以减少数据库操作。

 

在服务管理界面上可以动态的增加 / 删除 / 修改验证规则,在服务的调用时增加 SoapHandler ,执行过程如下:

1.  SOAPMessageContext 中获取请求 URL ,通过 URL 获取 OperationID

2.   根据 operationID 从缓存中获取请求或响应对应的所有验证规则。

3.  循环验证开始

4.  根据 ValidateKeySOAPMessageContext 中获取请求 / 响应中对应的值。

5.  匹配 ValidateRule 对应的正则表达式,如果不匹配,则 fail-fast 直接抛出运行时异常;匹配则验证下一个。

6.  循环验证结束。

 

数据操作以及正则表达式验证大家可以自己实现,下面简单写了一个 handler ,只是为了验证通过 xpath 获取 soap request 中的 value ,如果有兴趣大家可以自己完善。

 

package com.hp.test.cxf.handlers;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.xml.sax.InputSource;


public class ValidationHandler implements SOAPHandler<SOAPMessageContext> {

	public Set<QName> getHeaders() {
		// TODO Auto-generated method stub
		return null;
	}

	public void close(MessageContext arg0) {
		// TODO Auto-generated method stub
		
	}

	public boolean handleFault(SOAPMessageContext arg0) {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean handleMessage(SOAPMessageContext smc) {
		Boolean outboundProperty = (Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
		if (outboundProperty.booleanValue()) {
			//System.out.println("Out:"+smc.toString());
	    	return true;
	    } else {
	    	try{
	    		//从缓存中获取此URL(operation)对应的所有验证规则
	    		//循环验证key-rule
	    		SimpleNamespaceContext nsContext = new SimpleNamespaceContext();  
	            nsContext.setNamespace("soapenv",  "http://schemas.xmlsoap.org/soap/envelope/"); // instead of "SOAP-ENV"  
	            nsContext.setNamespace("cxf",   "http://cxf.test.hp.com/"); 
		    	String name = getDataXpath(smc.getMessage(),
		    			"/soapenv:Envelope/soapenv:Body/cxf:Person/name/child::text()",
		    			nsContext);
		    	//if(!name.matchs(rule)){throw new RuntimeException("name is invalid!");}
		    	//循环结束
	    	}catch(Exception e){e.printStackTrace();}
	    	return true;
	    }
	}
	
	public String getDataXpath( SOAPMessage message, String expression, NamespaceContext nsContext )   
    		throws java.io.IOException, javax.xml.soap.SOAPException, javax.xml.xpath.XPathExpressionException {  
	    ByteArrayOutputStream out = new ByteArrayOutputStream();  
	    message.writeTo(out);  
	    InputSource inputSource = new InputSource(    
	        new ByteArrayInputStream(out.toByteArray())   
	    );  
	
	    XPathFactory factory    = XPathFactory.newInstance();  
	    XPath xPath             = factory.newXPath();  
	    if (nsContext != null) xPath.setNamespaceContext( nsContext );  
	        
	    XPathExpression xpathExpression = xPath.compile( expression );  
	    return xpathExpression.evaluate( inputSource );  
	}      
}
class SimpleNamespaceContext implements NamespaceContext {  
    private Map<String,String> map;  
    
    public SimpleNamespaceContext() {  
        map = new HashMap<String,String>();  
    }  
      
    public void setNamespace(  
        String prefix,  
        String namespaceURI  
    ){  map.put(prefix, namespaceURI); }  
      
    // !!! doesn't fully implement getNamespaceURI API spec !!!  
    public String getNamespaceURI(  
        String prefix  
    ){  return map.get(prefix); }  
      
    // !!! doesn't fully implement getPrefix API spec !!!  
    public String getPrefix( String namespaceURI ){  
        SinglePrefixCollector collector = new SinglePrefixCollector();  
        collectPrefixes( namespaceURI, collector );  
        return collector.getResult();  
    }  
   
    // !!! doesn't fully implement getPrefixes API spec !!!  
    public Iterator getPrefixes( String namespaceURI ){  
        MultiPrefixCollector collector = new MultiPrefixCollector();  
        collectPrefixes( namespaceURI, collector );  
        return collector.getResult();  
    }  
   
    protected void collectPrefixes( String namespaceURI, PrefixCollector collector  ) {  
        Iterator<String>  iterator = map.keySet().iterator();   
        while( iterator.hasNext() ) {  
            String prefix = iterator.next();  
            if ( getNamespaceURI(prefix).equals(namespaceURI) ) {  
                boolean addMore = collector.addPrefix(prefix);  
                if(! addMore ) break;  
            }  
        }  
    }  
   
    protected interface PrefixCollector {  
        // template method for subclasses  
        // return: true - continue collecting; false - stop collecting.  
        boolean addPrefix(String prefix);  
    }  
   
    static protected class SinglePrefixCollector implements PrefixCollector {  
        private String prefix = null;  
        // returns false to stop further additions as it can only hold one prefix  
        public boolean addPrefix( String prefix ) { this.prefix = prefix; return false; }  
        public String getResult(){ return prefix; }  
    }  
   
    static protected class MultiPrefixCollector implements PrefixCollector {  
        private List<String> prefixes = new ArrayList<String>();  
        // returns true as it can hold more than one prefix  
        public boolean addPrefix( String prefix ) { prefixes.add(prefix); return true; }  
        public Iterator getResult() { return prefixes.iterator(); }  
    }  
} 
 

 

请求的 wsdl 如下

 

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cxf="http://cxf.test.hp.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <cxf:Person>
         <name>1</name>
         <address>2</address>
         <phone>3</phone>
         <email>eddis</email>
         <addresslist>
            <address>
               <address>8</address>
               <test>9</test>
            </address>
         </addresslist>
      </cxf:Person>
   </soapenv:Body>
</soapenv:Envelope>
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值