How can I transfer data from a SOAP handler to a webservice client?

(Following this question: Getting a raw XML response from a Java web service client )

I have a SOAP message handler that is able to receive a raw web service XML response. I need to get this XML in the webservice client so that I can perform some XSL conversions in response before sending it in my path. I'm having trouble finding a good way to get data from a SOAP handler that captures incoming messages and makes raw XML available to the generated (from WSDL) web service client. Any ideas if possible?


I came up with something like this:

public class CustomSOAPHandler implements javax.xml.ws.handler.soap.SOAPHandler<javax.xml.ws.handler.soap.SOAPMessageContext>
{
    private String myXML;
    public String getMyXML()
    {
        return myXML;
    }
    ...
    public boolean handleMessage(SOAPMessageContext context)
    {
        ...
        myXML = this.getRawXML(context.getMessage());
    }

    //elsewhere in the application:
    ...
    myService.doSomething(someRequest);
    for (Handler h: ((BindingProvider)myService).getBinding().getHandlerChain())
    {
        if (h instanceof CustomSOAPHandler )
        {
            System.out.println("HandlerResult: "+ ((CustomSOAPHandler )h).getMyXML());
        }
    }

. . XML , , . - ?

+7
4

JAXB XML. , , webservice XML, POJO, , POJO XML, .

+2

, , , , . , ThreadLocal , , .

secoond, , , . WS , invocationProperties SOAP responseContext, , , . ResponseContext . , ResponseContext , , get null, Application Scoped, invocationProperties, , , , . , / (Google: jaxws), , jax-ws, .

, https://jax-ws.java.net/nonav/jax-ws-20-fcs/arch/com/sun/xml/ws/api/message/Packet.html.

, . , JAXB, - "", , , .

.

+4

, /:

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; DR

Metro JAX WS RI MessageContext.Scope.APPLICATION:

, . , BindingProvider. . , , , , . MessageContext.Scope.APPLICATION, . invoke 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 :

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);
+2
source

Alternatively, instead of putting the request / response details in a soapy context (in my case, this did not work), you can put it in ThreadLocal. So you need SOAPHandlerwhat @gavenkoa described (ty), but add it to the instance ThreadLocal, not the soap context.

+1
source

All Articles