Search code examples
javasoapcxf

CXF message's context outside of interceptors


I'm sending a SOAP message using apache cxf and what I want is to get both request and response payloads after the call is finished. Currently I'm using two interceptors and put payloads into messages' context like that message.getExchange().put(ExchangeContextEnum.RESPONSE_PAYLOAD.toString(), new String(payload, Charset.forName(StandardCharsets.UTF_8.name())));.

I don't want to process them right away in the interceptor itself because I need requests and responses for the series of calls. Also, I'd like to avoid making any kind of storage for the sake of simplicity and not having to deal with possible concurrency issues.

Can I get those values after the call is finished or the context is completely lost at this point?

Some code:

webService.call(object)
//here i'd like to get payloads

Interceptor for response:

public class LogInInterceptor extends AbstractPhaseInterceptor<Message> {

public LogInInterceptor() {
    super(Phase.RECEIVE);
}

@Override
public void handleMessage(Message message) throws Fault {
    InputStream in = message.getContent(InputStream.class);
    byte payload[] = new byte[0];
    try {
        payload = IOUtils.readBytesFromStream(in);
    } catch (IOException e) {
        e.printStackTrace();
    }
    ByteArrayInputStream bin = new ByteArrayInputStream(payload);
    message.setContent(InputStream.class, bin);

    message.getExchange().put(ExchangeContextEnum.RESPONSE_PAYLOAD.toString(), new String(payload, Charset.forName(StandardCharsets.UTF_8.name())));
}
}

Interceptor for request:

public class WSSLogOutInterceptor extends AbstractSoapInterceptor {

public WSSLogOutInterceptor() {
    super(Phase.USER_PROTOCOL);
}

@Override
public void handleMessage(SoapMessage message) throws Fault {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
        SOAPMessage messageContent = message.getContent(SOAPMessage.class);

        messageContent.writeTo(baos);
        message.getExchange().put(ExchangeContextEnum.REQUEST_PAYLOAD.toString(), baos.toString());

    } catch (SOAPException | IOException e) {
        throw new Fault(e);
    }
}
}

Solution

  • I ended up with the following solution:

    Instead of putting values in message's exchange i simply do message.put(key, value) in the interceptor. To get those values after the call you need to get response context like that (String) ((BindingProvider) webService).getResponseContext().get(key) where key is the same value you used before to put payload in the message. Now here's the problem - you won't find values that you put in the outgoing chain in response context. You can use simple workaround and put value in the exchange of the message and then, in the ingoing chain get it and put it into message. Pay attention to the phase I used (POST_PROTOCOL), it'd helpful if you use WSS.

    Here's the code:

    public class LoggingOutPayloadInterceptor extends AbstractSoapInterceptor {
    
    public static final String OUT_PAYLOAD_KEY = "use.your.package.name.OUT_PAYLOAD_KEY";
    
    public LoggingOutPayloadInterceptor() {
        super(Phase.POST_PROTOCOL);
    }
    
    @Override
    public void handleMessage(SoapMessage soapMessage) throws Fault {
    
        Document document = soapMessage.getContent(SOAPMessage.class).getSOAPPart();
        StringWriter stringWriter = new StringWriter();
        try {
            TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(stringWriter));
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    
        soapMessage.getExchange().put(OUT_PAYLOAD_KEY, stringWriter.toString());
    }
    

    }

    public class LoggingInPayloadInterceptor extends AbstractSoapInterceptor {
    
    public static final String IN_PAYLOAD_KEY = "use.your.package.name.IN_PAYLOAD";
    
    public LoggingInPayloadInterceptor() {
        super(Phase.POST_PROTOCOL);
        addAfter(SAAJInInterceptor.class.getName());
    }
    
    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        Document document = message.getContent(SOAPMessage.class).getSOAPPart();
        StringWriter stringWriter = new StringWriter();
        try {
            TransformerFactory.newInstance().newTransformer().transform(new DOMSource(document), new StreamResult(stringWriter));
        } catch (TransformerException e) {
            e.printStackTrace();
        }
    
        message.put(IN_PAYLOAD_KEY, stringWriter.toString());
        message.put(LoggingOutPayloadInterceptor.OUT_PAYLOAD_KEY, message.getExchange().get(LoggingOutPayloadInterceptor.OUT_PAYLOAD_KEY));
    }
    

    }

    webService.call(...);
    String inPayload = (String)((BindingProvider)webService).getResponseContext().get(LoggingInPayloadInterceptor.IN_PAYLOAD_KEY);
    String outPayload = (String) ((BindingProvider) webService).getResponseContext().get(LoggingOutPayloadInterceptor.OUT_PAYLOAD_KEY);