Extracting textContent from server soap fault exception - java

Below is the server side exception returned to the client.
<SOAP-ENV:Envelope xmlns:SOAP-
ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/><SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring xml:lang="en">MerchantException</faultstring>
<detail>Invalid Store ID</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I'm using JAX-WS and below is my catch block.
catch(ServerSOAPFaultException ssfe) {
String textContent = ssfe.getFault().getTextContent();
}
but I'm not able to extract the detail 'invalid store id'. Even I tried the following one as well, String detail = ssfe.getFault().getDetail().getTextContent();

Related

SOAP XML request returning "Request is not well formed" fault

I am converting Python code to Java. The code is SOAP 1.5 client code which communicates with a SOAP server endpoint.
What doesn't make sense is that the Python code sends the XML request and gets the accepted response from the server. With the Java code however, the response is a fault stating "Request is not well formed".
Below I am showing the XML requests, the one which is sent in Python and the other in Java. How can the Java one sent by Java return a fault, but the Python is fine / accepted. They are both valid requests. Or perhaps I am missing something obvious.
Request in Python :
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://www.w3.org/2005/08/addressing"
xmlns:cs="urn://Ocpp/Cp/2012/06/">
<SOAP-ENV:Header>
<cs:chargeBoxIdentity>Test</cs:chargeBoxIdentity>
<wsa:MessageID>Fake OCPP571322528896</wsa:MessageID>
<wsa:Action>/ChangeConfiguration</wsa:Action>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:changeConfigurationRequest>
<cs:key>LaMa_ConnectionRate</cs:key>
<cs:value>5120</cs:value>
</cs:changeConfigurationRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Request in Java :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:cs="urn://Ocpp/Cp/2012/06/"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<SOAP-ENV:Header>
<cs:chargeBoxIdentity>Test</cs:chargeBoxIdentity>
<wsa:Action>/ChangeConfiguration</wsa:Action>
<wsa:MessageID>Fake OCPP571322528896</wsa:MessageID>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:changeConfigurationRequest>
<cs:key>LaMa_ConnectionRate</cs:key>
<cs:value>5120</cs:value>
</cs:changeConfigurationRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Fault response to Java :
<?xml version="1.0" encoding="UTF-8"?><env:Envelope
xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header/>
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
</env:Code>
<env:Reason>
<env:Text xml:lang="en-US">XML Request is not well formed!</env:Text>
</env:Reason>
</env:Fault>
</env:Body>
</env:Envelope>
Update :
My Java code should be sending "http://www.w3.org/2003/05/soap-envelope" for "SOAP-ENV", as shown below in my code. However it somehow sends "http://schemas.xmlsoap.org/soap/envelope/" instead. I don't understand why.
// SOAP Envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope");

How to capture soap error response for an Invalid data in request?

I am able to successfully log request and response for a valid soap request(class generated through wsimport) but couldn't capture the xml content when an exception is thrown(when a node in the request is filled with invalid data). I could get the details of response but I want to capture only the xml part of the raw response. I have tried SOAPFaultException but that gives only the exception message rather than the full envelope with body of the response.How do I capture the exception with only the xml content in the exception/error thrown.
Note: I know I can parse the error(raw response) and pull the xml content but I am wondering if there is simple way/method to get the xml content like below. The content should look like(response captured from Soap UI tool)
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<env:Header xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<wsa:Action>http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</wsa:Action>
<wsa:MessageID>urn:uuid:xyz</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:xyz</wsa:RelatesTo>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
</env:Header>
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">The 'http://www.fakexyz.com/schemas/xyz:xyz' element is invalid - The value '123' is invalid according to its datatype 'String' - The Pattern constraint failed.
Please revise your data fields and make sure that message is correctly formatted.</soap:Text>
</soap:Reason>
<detail>
<faulttype>Schema</faulttype>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
After exploring more and trying, I found that we need to have a class which should implement SoapHandler interface, this gives you pretty much what was needed.
I overrode handleFault method as below.
public boolean handleFault(SOAPMessageContext context) {
System.out.println("==============================================RESPONSE(ERROR)=======================================\r\n");
String[] abc= context.get(MessageContext.HTTP_RESPONSE_HEADERS).toString().split("],");
for(String httpheader:abc) {
System.out.println(httpheader+"],");
}
System.out.println("\r\n");
SOAPMessage message= context.getMessage();
try {
Source source = message.getSOAPPart().getContent();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
transformer.transform(source, new StreamResult(System.out));
} catch (Exception e) {
System.out.println("Response has errors!!");
}
return false;
}
This gave me error info in formatted xml as well as with http headers.

JAX-WS fault changes in mtom service when logging is enabled through SOAPHandler

I have a jax-ws service published in a standalone server application. This service uses mtom to receive documents
As advised in the answer to this question:
Tracing XML request/responses with JAX-WS
I use a handler for soap message logging for the service as below:
public boolean handleMessage(SOAPMessageContext smc){
performLoggingActions(smc);
return true;
}
The logger method is as below:
private void performLoggingActions(SOAPMessageContext smc) {
ByteArrayOutputStream bout = null;
try {
Boolean isOutBound = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
SOAPMessage message = smc.getMessage();
//More stuff
} catch (Exception e) {
logger.error(String.format("Error in logSoapMessage! Error: %s ", e.getMessage()), e);
} finally {
IOUtils.closeQuietly(bout);
}
}
When client sends a valid request, there is no problem in logging. Everything is logged as expected.
However, if I send an invalid content id in request via SOAP UI, the logging fails in line SOAPMessage message = smc.getMessage(); and I have the below error:
Error in logSoapMessage! Error: No such MIME Part: Part=5
java.lang.IllegalStateException: No such MIME Part: Part=5
at com.sun.xml.internal.org.jvnet.mimepull.DataHead.read(DataHead.java:138)
at com.sun.xml.internal.org.jvnet.mimepull.MIMEPart.read(MIMEPart.java:85)
The problem is, when this occurs, the message does not propogate to service level and the service responds to the client with below fault:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>unexpected XML tag. expected: somenamespace but found: {http://www.w3.org/2004/08/xop/include}Include</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
When I disable soap logging and send a fault request, the message is propagated to service level, to the #WebService annotated class, and I receive a similar expection when trying to read the mtom content.
However, in that case the error is reflected in the response as fault string:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>No such MIME Part: Part=5</faultstring>
</S:Fault>
</S:Body>
</S:Envelope>
I would expect the same fault regardless of the existence of the logging handler.
As you can see, I am catching all exceptions in logging handler but the service response changes according to the existence of the logging handler.
I am doing something wrong? My requirement is getting the same fault with and without logging handler.
Regards
EDIT : Entire stack trace of the error added:
Error in logSoapMessage! Error: No such MIME Part: Part=5
java.lang.IllegalStateException: No such MIME Part: Part=5
at com.sun.xml.internal.org.jvnet.mimepull.DataHead.read(DataHead.java:138)
at com.sun.xml.internal.org.jvnet.mimepull.MIMEPart.read(MIMEPart.java:85)
at com.sun.xml.internal.ws.encoding.MIMEPartStreamingDataHandler$StreamingDataSource.getInputStream(MIMEPartStreamingDataHandler.java:98)
at com.sun.xml.internal.org.jvnet.staxex.Base64Data.get(Base64Data.java:315)
at com.sun.xml.internal.org.jvnet.staxex.Base64Data.length(Base64Data.java:357)
at com.sun.xml.internal.ws.encoding.MtomCodec$MtomXMLStreamReaderEx.getTextCharacters(MtomCodec.java:533)
at com.sun.istack.internal.XMLStreamReaderToContentHandler.handleCharacters(XMLStreamReaderToContentHandler.java:244)
at com.sun.istack.internal.XMLStreamReaderToContentHandler.bridge(XMLStreamReaderToContentHandler.java:155)
at com.sun.xml.internal.ws.message.stream.StreamMessage.writePayloadTo(StreamMessage.java:375)
at com.sun.xml.internal.ws.message.stream.StreamMessage.writeTo(StreamMessage.java:460)
at com.sun.xml.internal.ws.message.AbstractMessageImpl.readAsSOAPMessage(AbstractMessageImpl.java:196)
at com.sun.xml.internal.ws.handler.SOAPMessageContextImpl.getMessage(SOAPMessageContextImpl.java:82)
at com.ibtech.smg.esb.jaxws.handler.JAXWSSOAPLoggingHandler.performLoggingActions(JAXWSSOAPLoggingHandler.java:54)
at com.ibtech.smg.esb.jaxws.handler.JAXWSSOAPLoggingHandler.handleMessage(JAXWSSOAPLoggingHandler.java:36)
at com.ibtech.smg.esb.jaxws.handler.JAXWSSOAPLoggingHandler.handleMessage(JAXWSSOAPLoggingHandler.java:1)
at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandleMessage(HandlerProcessor.java:295)
at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandlersRequest(HandlerProcessor.java:138)
at com.sun.xml.internal.ws.handler.ServerSOAPHandlerTube.callHandlersOnRequest(ServerSOAPHandlerTube.java:136)
at com.sun.xml.internal.ws.handler.HandlerTube.processRequest(HandlerTube.java:118)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:639)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:598)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:583)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:480)
at com.sun.xml.internal.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:312)
at com.sun.xml.internal.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:606)
at com.sun.xml.internal.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:257)
at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handleExchange(WSHttpHandler.java:108)
at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handle(WSHttpHandler.java:93)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:90)
at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:96)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:93)
at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:690)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:90)
at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:662)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1157)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:627)
at java.lang.Thread.run(Thread.java:809)
Could you please paste the entire stack trace and the code in your SOAP handler? Is this line getting printed in your logs? logger.error(String.format("Error in logSoapMessage! Error: %s ", e.getMessage()), e);

Disable output escaping for spring ws

I have a bit of a problem with spring-ws WebserviceTemplate
I've created a WebserviceMessage like this
public WebServiceMessage createWebServiceMessage(String innerEnvelope)
{
SOAPMessage soapMsg=null;
MessageFactory factory;
try
{
factory = MessageFactory.newInstance();
soapMsg = factory.createMessage();
SOAPPart part = soapMsg.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
SOAPBody body = envelope.getBody();
QName ejbName = new QName(EJB_VALUE,"lustraciaOsoby",EJB_PREFIX);
SOAPElement ejbElement =body.addBodyElement(ejbName);
ejbElement.addNamespaceDeclaration(SOAP_ENV_PREFIX, SOAP_ENV_VALUE);
ejbElement.setAttribute("soapenv:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
QName transName=new QName(TRANS_ELEMENT);
SOAPElement transElement = ejbElement.addChildElement(transName);
transElement.addNamespaceDeclaration(XSI_PREFIX, XSI_VALUE);
transElement.addNamespaceDeclaration(XSD_PREFIX, XSD_VALUE);
transElement.setAttribute("xsi:type", "xsd:string");
transElement.addTextNode(innerEnvelope);
soapMsg.saveChanges();
} catch (SOAPException e)
{
LOGGER.debug("Error while creating message",e);
}
return (WebServiceMessage)new SaajSoapMessage(soapMsg);
}
which result in XML that is looking like this(this is 100% valid request for this web service, with usage of standard HttpConnection it was returning valid response)
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/><SOAP-ENV:Body><ejb:lustraciaOsoby xmlns:ejb="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<transXmlEnc xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">
<TransEnv xmlns="http://schemas.mvsr.sk/clk/clk2/lustracia_osoby_in_transxml.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
cPageSize="50" cRecNoFrom="0">
<LOI><SI>2,3,5,8,19</SI><PR>Mrkvička</PR><PR_PARTIAL>false</PR_PARTIAL><PR_FUZZY>false</PR_FUZZY><ME>Ján</ME><ME_PARTIAL>false</ME_PARTIAL><ME_FUZZY>false</ME_FUZZY><LV_ANYNAME>false</LV_ANYNAME>
</LOI></TransEnv>
</transXmlEnc>
</ejb:lustraciaOsoby>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Just for info, that escaped part is like soap in soap, which is parsed on server side.
The problem is, when I execute this with sendSourceAndReceiveToResult, the final SOAP that is sent is in this form
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ejb:lustraciaOsoby
xmlns:ejb="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<transXmlEnc xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">
&lt;TransEnv xmlns=&quot;http://schemas.mvsr.sk/clk/clk2/lustracia_osoby_in_transxml.xsd&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; cPageSize=&quot;50&quot; cRecNoFrom=&quot;0&quot;&gt;&lt;LOI&gt;&lt;SI&gt;2,3,5,8,19&lt;/SI&gt;&lt;PR&gt;Mrkvi&#269;ka&lt;/PR&gt;&lt;PR_PARTIAL&gt;false&lt;/PR_PARTIAL&gt;&lt;PR_FUZZY&gt;false&lt;/PR_FUZZY&gt;&lt;ME&gt;J&#225;n&lt;/ME&gt;&lt;ME_PARTIAL&gt;false&lt;/ME_PARTIAL&gt;&lt;ME_FUZZY&gt;false&lt;/ME_FUZZY&gt;&lt;LV_ANYNAME&gt;false&lt;/LV_ANYNAME&gt;&lt;/LOI&gt;&lt;/TransEnv&gt;
</transXmlEnc>
</ejb:lustraciaOsoby>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Its pretty hard to spot the difference, but the trick is that all & are replaced with &amp which is a problem, because the parser on the server side can't parse it due to Reference is not allowed in prologue error. Without this weird escape, the request works just fine.
So my question is, is there any way to disable this additional escaping ?
Finally i was able to resolve this. The problem was that input that was coming to transElement.addTextNode(innerEnvelope); was already escaped by StringEscapeUtils and apache tried to escape it again ,what cause the reescapting of & to &amp

JAX-WS SOAP Faults - parse the details of the error in a SOAPFaultException

I'm having the need to get the details of error if it's a faulty soap request.
I'm using JAX-WS to create web service client. My problem is that during a faulty transaction, the web service client is able to catch the SOAPFaultException but without detail:
javax.xml.ws.soap.SOAPFaultException: Component Interface API. at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
If I send the request through SOAPUI, I can get the response with details as:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>Component Interface API.</faultstring>
<detail>
<IBResponse type="Error">
<DefaultTitle>Integration Broker Response</DefaultTitle>
<StatusCode>20</StatusCode>
<MessageSetID>180</MessageSetID>
<MessageID>117</MessageID>
<DefaultMessage>You are allowed to claim one meal per day</DefaultMessage>
<MessageParameters>
<keyinformation>
<EMPLID>112233</EMPLID>
</keyinformation>
</MessageParameters>
</IBResponse>
</detail>
</SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Did I miss any configuration in web service client? Many thanks in advance.
To get details from the javax.xml.ws.soap.SOAPFaultException:
try {
//... invoke service via client
} catch (javax.xml.ws.soap.SOAPFaultException soapFaultException) {
javax.xml.soap.SOAPFault fault = soapFaultException.getFault(); //<Fault> node
javax.xml.soap.Detail detail = fault.getDetail(); // <detail> node
Iterator detailEntries = detail.getDetailEntries(); //nodes under <detail>
//application / service-provider-specific XML nodes (type javax.xml.soap.DetailEntry) from here
}
See associated javadocs for methods / info you can get from these constructs:
SoapFaultException
SOAPFault
Detail
DetailEntry

Categories

Resources