传递请求/响应消息体的处理程序示例:
public class MsgLogger implements SOAPHandler<SOAPMessageContext> {
public static String REQEST_BODY = "com.evil.request";
public static String RESPONSE_BODY = "com.evil.response";
@Override
public Set<QName> getHeaders() {
return null;
}
@Override
public boolean handleMessage(SOAPMessageContext context) {
SOAPMessage msg = context.getMessage();
Boolean beforeRequest = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(32_000);
context.getMessage().writeTo(baos);
String key = beforeRequest ? REQEST_BODY : RESPONSE_BODY;
context.put(key, baos.toString("UTF-8"));
context.setScope(key, MessageContext.Scope.APPLICATION);
} catch (SOAPException | IOException e) { }
return true;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return true;
}
@Override
public void close(MessageContext context) { }
}
要注册处理程序并使用保留的属性:
BindingProvider provider = (BindingProvider) port;
List<Handler> handlerChain = bindingProvider.getBinding().getHandlerChain();
handlerChain.add(new MsgLogger());
bindingProvider.getBinding().setHandlerChain(handlerChain);
Req req = ...;
Rsp rsp = port.serviceCall(req); // call WS Port
// Access saved message bodies:
Map<String, Object> responseContext = provider.getResponseContext();
String reqBody = (String) responseContext.get(MsgLogger.REQEST_BODY);
String rspBody = (String) responseContext.get(MsgLogger.RESPONSE_BODY);
TL;博士
Metro JAX WS RI 文档说关于MessageContext.Scope.APPLICATION
属性:
消息上下文对象还可以保存客户端或提供者设置的属性。例如,端口代理和调度对象都扩展了BindingProvider
. 可以从两者中获取消息上下文对象来表示请求或响应上下文。处理程序可以读取请求上下文中设置的属性,并且处理程序可以在传递给它们的消息上下文对象上设置属性。如果这些属性与范围一起设置,MessageContext.Scope.APPLICATION
那么它们将在客户端的响应上下文中可用。在服务器端,一个上下文对象被传递到一个Provider
.
metro-jax-ws/jaxws-ri/rt/src/main/java/com/sun/xml/ws/api/message/Packet.java
包含属性:
/**
* Lazily created set of handler-scope property names.
*
* <p>
* We expect that this is only used when handlers are present
* and they explicitly set some handler-scope values.
*
* @see #getHandlerScopePropertyNames(boolean)
*/
private Set<String> handlerScopePropertyNames;
另一方面metro-jax-ws/jaxws-ri/rt/src/main/java/com/sun/xml/ws/client/ResponseContext.java
是Map
with 的实现:
public boolean containsKey(Object key) {
if(packet.supports(key))
return packet.containsKey(key); // strongly typed
if(packet.invocationProperties.containsKey(key))
// if handler-scope, hide it
return !packet.getHandlerScopePropertyNames(true).contains(key);
return false;
}
在SOAPHandler
我们可以将属性标记为APPLICATION
而不是默认值MessageContext.Scope.HANDLER
:
/**
* Property scope. Properties scoped as <code>APPLICATION</code> are
* visible to handlers,
* client applications and service endpoints; properties scoped as
* <code>HANDLER</code>
* are only normally visible to handlers.
*/
public enum Scope {APPLICATION, HANDLER};
经过:
/**
* Sets the scope of a property.
*
* @param name Name of the property associated with the
* <code>MessageContext</code>
* @param scope Desired scope of the property
* @throws java.lang.IllegalArgumentException if an illegal
* property name is specified
*/
public void setScope(String name, Scope scope);