I need to implement a web service client for a third-party web service. Unfortunately the web service operator decided to send a HTTP status code 400 if a "normal" fault occurred. That means if something is going wrong the web service sends something like this in the body
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<soapenv:Fault>
<faultcode>ERROR</faultcode>
<faultstring>[M0002] The following dealer information was not accepted. [C07AB02157XX]</faultstring>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
and sets the HTTP-StatusCode to 400 and Content-Type to 'text/xml'. This results in a WebServiceException in my code which does not contain the Fault itself. In such case my stacktrace looks like this:
javax.xml.ws.WebServiceException: Could not send Message.
at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:183)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:145)
at com.sun.proxy.$Proxy104.dihMessage(Unknown Source)
at de.dmsserver.core.service.manufacturer.hyundai.dih.masterdata.MasterDataContext.requestSinglePartNumber(MasterDataContext.java:154)
... 9 more
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '400: Bad Request' when communicating with [...]
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1618)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1625)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1570)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1371)
at org.apache.cxf.ext.logging.LoggingOutputStream.postClose(LoggingOutputStream.java:53)
at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:228)
at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:56)
at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:228)
at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:56)
at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:228)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:671)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:528)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:439)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:354)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:312)
at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:140)
... 11 more
Now I can not figure out how to get access to the original body with the Fault itself.
I played a bit and adding my own OutInterceptors with Phase.SEND
class MyOutInterceptor extends AbstractPhaseInterceptor<Message> {
public MyOutInterceptor() {
super(Phase.SEND);
}
@Override
public void handleFault(Message message) {
// ...
}
@Override
public void handleMessage(Message message) throws Fault {
// ...
}
}
In such a case the handleFault method is fired, but I can't figure out how to access the response body as message.getContent(InputStream.class) returns null.
It seems that Apache CXF - handle response with HTTP 400 code is exactly my problem. Unfortunately this question was not solved.
I've just found a solution for this problem after digging more about this in the net. I've found this request in apache jira https://issues.apache.org/jira/browse/CXF-4241 This solved my problem!