我们接着以前面的blog【HelloWord例子:客户端向请求SOAP消息中注入报头块(使用配置方式)】为例。在该例子基础上添加服务端的Handler,用来验证UUID值。
为了使例子更完整,我们需要一个服务端的SOAP Handler来处理客户端向出站SOAP消息中插入的报头块。我们来看看服务端都有什么变化。
HelloWord.java:
package ch03.ts;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.Holder;
@WebService
public interface HelloWord {
@WebMethod
void sayHello(@WebParam(name="name") String name,
@WebParam(name="wh",mode=WebParam.Mode.INOUT) Holder<String> wh,
@WebParam(name="hf",mode=WebParam.Mode.OUT) Holder<String> hf);
}
HelloWordImpl.java(注意:这里添加了@HandlerChain(file="handler-chain-server.xml")注解,也就是服务器端的注解是添加在SIB上的):
package ch03.ts;
import javax.jws.HandlerChain;
import javax.jws.WebService;
import javax.xml.ws.Holder;
@WebService(endpointInterface = "ch03.ts.HelloWord")
@HandlerChain(file = "handler-chain-server.xml")
public class HelloWordImpl implements HelloWord {
@Override
public void sayHello(String name, Holder<String> wh, Holder<String> hf) {
System.out.println(name + "!" + wh.value);
wh.value = "你们好";
hf.value = "同学们";
}
}
HelloWordPublisher.java:
package ch03.ts;
import javax.xml.ws.Endpoint;
public class HelloWordPublisher {
public static void main(String[] args) {
Endpoint.publish("http://localhost:7654/ts", new HelloWordImpl());
}
}
新增加的服务器端Handler:UUIDValidator.java
package fibC;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
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.ws.soap.SOAPFaultException;
/**
* 服务器端验证UUID值
* @author fuhd
*/
public class UUIDValidator implements SOAPHandler<SOAPMessageContext> {
private static final int UUIDVARIANT = 2; //layout
private static final int UUIDVERSION = 4; //version
@SuppressWarnings({ "rawtypes"})
@Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean resp = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if(!resp){
try {
SOAPMessage msg = context.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
if(hdr == null)
generateSOAPFault(msg, "No message header.");
Iterator it = hdr.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);
if(it == null || !it.hasNext())
generateSOAPFault(msg, "No header block for next actor.");
Node next = (Node)it.next();
String value = (next == null)?null:next.getValue();
if(value == null)
generateSOAPFault(msg, "No UUID in header block.");
UUID uuid = UUID.fromString(value.trim());
if(uuid.variant() != UUIDVARIANT || uuid.version() != UUIDVERSION)
generateSOAPFault(msg, "Bad UUID variant or version");
System.out.println(value.trim());
} catch (SOAPException e) {
e.printStackTrace();
}
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) {}
@Override
public Set<QName> getHeaders() {
return null;
}
private void generateSOAPFault(SOAPMessage msg,String reason){
try {
SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
SOAPFault fault = body.addFault();
fault.setFaultString(reason);
throw new SOAPFaultException(fault);
} catch (SOAPException e) {
e.printStackTrace();
}
}
}
handler-chain-server.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<javaee:handler-chains xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<javaee:handler-chain>
<javaee:handler>
<javaee:handler-class>fibC.UUIDValidator</javaee:handler-class>
</javaee:handler>
</javaee:handler-chain>
</javaee:handler-chains>
UUIDValidator在服务层校验入站的SOAP消息。这个校验器需要访问整个SOAP消息,而不仅仅是SOAP消息体,因此它必须实现SOAPHandler接口,而不是一个LogicalHandler接口。
注意,上例中任何一部分校验失败均会抛出一个SOAPFaultException异常,重新包装为SOAP1.1和SOAP1.2错误。通过对错误的重新包装,我们可以忽略SOAP两个不同版本之间的差异。