Java - Consume SOAP Web Service from String XML Envelope - java

Using SoapUI I have built the following XML envelope and encapsulated it in a String.
ProcessJournal is a method which has no parameters, and returns a string.
String soapText = "<Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:upd=\"http://webservices.vm.vmc/UpdateCMA/\">" +
"<Header/>" +
"<Body>" +
"<upd:ProcessJournal/>" +
"</Body>" +
"</Envelope>";
Now... I simply want to invoke the web service defined above. And have found some sample code to do so
// Create SoapMessage
MessageFactory msgFactory = MessageFactory.newInstance();
SOAPMessage message = msgFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
// Load the SOAP text into a stream source
byte[] buffer = soapText.getBytes();
ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
StreamSource source = new StreamSource(stream);
// Set contents of message
soapPart.setContent(source);
// -- DONE
message.writeTo(System.out);
//Try accessing the SOAPBody
SOAPBody soapBody = message.getSOAPBody();
The problem is, at message.getSOAPBody();, I get an error
XML-22103: (Fatal Error) DOMResult can not be this kind of node.
Apr 16, 2013 12:05:06 PM com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory createEnvelope
SEVERE: SAAJ0511: Unable to create envelope from given source
All the various samples I find, end up having the same type of error when getSOAPBody() is executed.

I don't know whether you ever found a solution to this. I've just recently been seeing the exact same error and it was due to a TransformerFactory not being set.
I used the TransformerFactory from the Saxon library - the jar for which can be obtained here.
I then set a system property which referenced the Saxon TransformerFactory:
System.setProperty("javax.xml.transform.TransformerFactory",
"net.sf.saxon.TransformerFactoryImpl");
The error then disappeared when I re-ran my code.
The above is just one way to set the TransformerFactory. There are a number of other ways to do this which I found here: stackoverflow.com/questions/11314604/

It looks like the problem was with the namespace prefixing in your soapText. I was able to execute your example without error and without manually setting any TransformerFactory simply by modifying your soapText as follows:
String soapText =
"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:upd=\"http://webservices.vm.vmc/UpdateCMA/\">" +
"<soapenv:Header/>" +
"<soapenv:Body>" +
"<upd:ProcessJournal/>" +
"</soapenv:Body>" +
"</soapenv:Envelope>";
Note the added soapenv: prefix in all the Soap elements in contrast to the upd prefix in your Soap service namespace.

Related

Dynamically adding namespace to SOAP Envelope in Java

I am new to all of this but I am trying to create a SOAP message and get stuck at the off, I am using Java 8 and the standard javax.xml.soap classes but seem unable to add namespaces to the Envelope
MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
SOAPPart part = message.getSOAPPart();
SOAPEnvelope envelope = part.getEnvelope();
envelope.addNamespaceDeclaration( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
If I try this at runtime I get the following error
NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces.
I have done this now by creating the required envelope definition as an XML String and then setting the SOAPPart content using that string

Unable to view reply in SOAP call

I'm currently working on a custom SOAP call to a specific domain beyond my control. I know the SOAP call fails but I cannot seem to grab the returned (wrong)value.
Right now I'm using the code below:
Document document = convertStringToDocument(this.MeldingString);
// System.out.println(document);
SOAPConnectionFactory myFct = SOAPConnectionFactory.newInstance();
MessageFactory myMsgFct = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SOAPMessage message = myMsgFct.createMessage();
SOAPConnection myCon = myFct.createConnection();
// Adding parts
SOAPPart mySPart = message.getSOAPPart();
SOAPEnvelope myEnvp = mySPart.getEnvelope();
// Escape the password for usage in header
String escpwd = StringEscapeUtils.escapeJava(this.Password);
// Header
MimeHeaders headers = message.getMimeHeaders();
headers.setHeader("Content-Type", "application/soap+xml;charset=UTF-8");
headers.setHeader("Authorization", this.Username + ":" + escpwd);
// Body
SOAPBody body = myEnvp.getBody();
body.addDocument(document);
// Sending
Core.getLogger("GetResultSOAPmsg").trace("Started");
URL endPt = new URL(
"URL-TO-MY-SERVICE");
System.setProperty("java.net.useSystemProxies", "true");
try {
SOAPMessage reply = myCon.call(message, endPt); "UTF-8");
}
catch(Exception e)
{
e.printStackTrace();
}
This yields the following error which is very common al throughout SO:
SEVERE: SAAJ0537: Invalid Content-Type. Could be an error message instead of a SOAP message
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Invalid Content-Type:text/html. Is this an error message instead of a SOAP response?
Now I have read most of these topics already and they explain how this problem is usually solved (namespaces, escaping URL, etc.) but I cannot seem to figure out what is wrong in my case. This is a private service and the other side is unfortunately unable to assist me in this case. The error could be anything from wrong certificates to misspelling the URL.
Therefore I would like to actually SEE onscreen what the actual reply is that was received when making the call. This is going to help me (assuming it's something like a 503, 404 or other page). Regardless of what I do and where I set my breakpoints, there is no information on Reply. It makes somewhat sense since it was unable to create said object but the entire message seems to be discarded.
In what way will I be able to see what the actual reply was to my call before it is discarded?
I think there's a problem with your header
headers.setHeader("Content-Type", "application/soap+xml;charset=UTF-8");
try something like
headers.setHeader("Content-Type", "application/xml;charset=UTF-8");
or
headers.setHeader("Content-Type", "application/json;charset=UTF-8");
depending on the content type that the content type accepted by the service

How do you add XML prolog in javax.xml.soap.SOAPBody

I am trying to send an XML document via SOAP to a server that requires the payload XML to contain an XML prolog e.g., <?xml version="1.0" encoding="utf-8" ?>. The following is very similar to the code I'm using:
SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();
SOAPPart soapPart = getSoapMessage().getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
soapHeader = envelope.getHeader();
soapBody = envelope.getBody();
soapHeader.detachNode();
SOAPBodyElement bodyElement = soapBody.addBodyElement(getEnvelope().createName("my_element_name"));
bodyElement.addAttribute(getEnvelope().createName("my_attribute_name"), "my_attribute_value");
bodyElement.addChildElement("my_child_element");
...
A XML prolog can only exist at the very start of a XML document.
From the XML Specification available here : http://www.w3.org/TR/2000/REC-xml-20001006#sec-prolog-dtd
The document type declaration must appear before the first element in the document.
Writing a prolog in the middle of a SOAP document, therefore, is invalid - and I doubt you'll find a SOAP library or implementation that will allow you to do that. There may be a requirement you and/or your "client" have misunderstood in requiring this.
You can try a XML validator softare (e.g. http://www.w3schools.com/xml/xml_validator.asp ), it should report an error for your expected result.
Here is how to add xml prolog declaration right before the first SOAP Envelope tag:
soapMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, Boolean.TRUE.toString());

HandleFault in CXF interceptors

I'm using CXf's fault out interceptor to intercept the exception from the web services method. That works fine within the handleMessage method..
Now I have two questions,
How do I had extra information to the Fault object apart from setting the faultcode?
Say if there is any error in the handleMessage method, the control goes to handleFault method but in the handle fault method it simply unwinds and logs something like - GetMth has thrown exception, unwinding now: java.lang.Exception. But the fault message(in xml format) is not being sent to the client as Output mesasage,
2. How do I make sure that the fault message is sent as SOAPfault to the clinet? (in the hanldeMessage below, i have place `f=null` to introduce the fault) Please Suggest!!!
I managed to write the xml content to the writer class with the below code, but am unable to pass this message to the client. I mean even after writing the message to the xmlwriter class and content being written fine to the console log, its not been sent to the client. i.e, I dont see the outbound message being sent nor printed when i turn on the monitors and the interceptor outbound logs. Could anyone please help me with this?
MessageFactory factory = getFactory(message);
SOAPMessage soapMessage = factory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPBody soapBody = soapPart.getEnvelope().getBody();
SOAPFault soapFault = soapBody.addFault();
soapFault.setFaultString("Strange");
W3CDOMStreamWriter writer1 = new SAAJStreamWriter(soapPart);
message.setContent(XMLStreamWriter.class, writer1);
message.setContent(SOAPMessage.class, soapMessage);
message.setContent(Node.class, soapMessage.getSOAPPart());
message.getInterceptorChain().add(SAAJOutEndingInterceptor.INSTANCE);
LOGS:
saaj the factory com.sun.xml.messaging.saaj.soap.ver1_2.SOAPMessageFactory1_2Impl#146ee9c
saaj the soapMessage com.sun.xml.messaging.saaj.soap.ver1_2.Message1_2Impl#1db52c8
saaj the soapPart com.sun.xml.messaging.saaj.soap.ver1_2.SOAPPart1_2Impl#17d6c1
saaj the soapsoapBodyPart [env:Body: null]
saaj the soapFault [env:Fault: null]
saaj the setFaultString Strange
saaj the messg {org.apache.cxf.message.Message.RESPONSE_CODE=200, HTTP.RESPONSE=org.apache.catalina.connector.ResponseFacade#2982bf, org.apache.cxf.headers.Header.list=[], wrote.envelope.start=true, org.apache.cxf.message.Message.ENCODING=UTF-8, org.apache.cxf.message.FaultMode=CHECKED_APPLICATION_FAULT, org.apache.cxf.binding.soap.SoapVersion=org.apache.cxf.binding.soap.Soap12#b16f5f, Content-Type=application/soap+xml, org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor.original.xml.writer=[StreamWriter: class com.ctc.wstx.sw.SimpleNsStreamWriter, underlying outputter: com.ctc.wstx.sw.BufferingXmlWriter#1144823], org.apache.cxf.interceptor.LoggingOutInterceptor.log-setup=true, org.apache.cxf.service.model.BindingFaultInfo=org.apache.cxf.service.model.BindingFaultInfo#106def2}
saaj the writer1 :
><pre><env:Header/><env:Body><env:Fault><env:Code><env:Value>env:Receiver</env:Value></env:Code><env:Reason><env:Text xml:lang="en-US">Strange</env:Text></env:Reason></env:Fault></env:Body> </pre>
Please advise.

Exception thrown when using Java Generic SOAPClient (SAAJ)?

I’m trying to use the following SOAPClient for Java (details which I’ve obtained from the following tutorial http://users.skynet.be/pascalbotte/rcx-ws-doc/saajpost.htm).
However, it seems to be throwing an exception.
Here is my code:
javax.xml.soap.SOAPMessage msg;
MessageFactory mf = MessageFactory.newInstance();
msg = mf.createMessage();
SOAPPart part = msg.getSOAPPart();
StreamSource source = new StreamSource(new File("samples/input1.xml”));
part.setContent(source);
msg.saveChanges();
String endpoint = "http://ws1.parasoft.com/glue/calculator";
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection conn = scf.createConnection();
javax.xml.soap.SOAPMessage response = conn.call(msg, endpoint);
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
Source sc = response.getSOAPPart().getContent();
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
StreamResult result = new StreamResult(ostream);
tf.transform(sc, result);
conn.close();
System.out.println(new String(ostream.toByteArray(), "UTF-8”));
In this example, we assume samples/input1.xml holds the following:
<s11:Envelope xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/">
<s11:Body>
<ns1:add xmlns:ns1="http://www.parasoft.com/wsdl/calculator/">
<ns1:x>248</ns1:x>
<ns1:y>365</ns1:y>
</ns1:add>
</s11:Body>
</s11:Envelope>
The sample web-service that I’m trying to use can be found here:
http://www.service-repository.com/client/operations
When running the above Java-code (using the SOAPClient library), the following exception is thrown:
Jul 19, 2012 3:50:11 AM com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection post
SEVERE: SAAJ0008: Bad Response; cannot find /calculator
Exception in thread "main" com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404cannot find /calculator
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:148)
at corebus.test.deprecated.TestMain.main(TestMain.java:1870)
Caused by: com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404cannot find /calculator
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:258)
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:144)
... 1 more
CAUSE:
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Bad response: (404cannot find /calculator
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.post(HttpSOAPConnection.java:258)
at com.sun.xml.internal.messaging.saaj.client.p2p.HttpSOAPConnection.call(HttpSOAPConnection.java:144)
Using this web-site, it seems the services is up and running, and working well.
I have even verified the service-endpoint is active, by conducted a simple cURL request, which surprisingly produces the correct output.
curl -H "Content-Type: text/xml; charset=utf-8" -H "SOAPAction:http://www.parasoft.com/wsdl/calculator/" -d#soap-request.xml http://ws1.parasoft.com/glue/calculator
The output produced is:
<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/‘>
<soap:Body>
<n:addResponse xmlns:n='http://www.parasoft.com/wsdl/calculator/‘>
<n:Result xsi:type='xsd:float'>613.0</n:Result>
</n:addResponse>
</soap:Body>
</soap:Envelope>
So, my question is: Firstly, what is wrong with the Java-code? And how could it be fixed? Or also, is there any other better/more-reliable Generic SOAPClient Library that would be recommended?
Have a look at the WSDL by attaching ?wsdl in your url in browser or somehow get he WSDL. Check if the WSDl specifies if it is a document style or PRC style and based on that prepare the input xml.
If possible use SOAP UI tool which can be very handy.

Categories

Resources