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.
Related
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
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.
I am trying to access SAOP API using SAAJ.
I have followed the same code that were present in other answers on creating a SOAP request body and
calling the SOAP API.
This particular service does not need any authentication (as mentioned in API doc) nor does it take any input parameters.
From WSDL: (copied only relevant content)
<xs:complexType name="getCustomerNames">
<xs:sequence/>
</xs:complexType>
...
<wsdl:operation name="getCustomerNames">
<wsdl:input message="tns:getCustomerNames" name="getCustomerNames"/>
<wsdl:output message="tns:getCustomerNamesResponse" name="getCustomerNamesResponse"/>
<wsdl:fault message="tns:SOAPException" name="SOAPException"/>
</wsdl:operation>
Below is the Java code that creates the soap body and calls the API
SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
SOAPConnection connection = scf.createConnection();
SOAPFactory sf = SOAPFactory.newInstance();
String serverURI = "com.webservices.services.authentication";
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL); // I tried without parameters as well
SOAPMessage message = mf.createMessage();
message.getSOAPHeader().detachNode();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("auth", serverURI);
Name bodyName = sf.createName("getCustomerNames", "auth", serverURI);
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
URL endpoint = new URL(urlendpoint); // urlendpoint is the one that I took from WSDL file service endpoint.
SOAPMessage response = connection.call(message, endpoint);
connection.close();
I get the below error message whenever I execute this. I could not understand why.. The same url is returning the
proper response when I execute curl command from Unix and post the same request xml that was created by above java code.
Feb 14, 2017 3:21:54 PM com.sun.xml.internal.messaging.saaj.soap.MessageImpl identifyContentType
SEVERE: SAAJ0537: Invalid Content-Type. Could be an error message instead of a SOAP message
com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Invalid Content-Type:text/html. Is this an error message instead of a SOAP response?
That error means that the server responds with an HTML page instead of a SOAP response. To debug this, you need to intercept the response and look at the content of the HTML page; it will probably contain more information about the problem.
I've been tasked with querying a soap client in java and i'm a bit confused as how to move forward.
The first thing i did was use the Wizdler chrome plugin to prototype my SOAP request. The soap "envelop" must be of this format I believe for it to work.
<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">
<Body>
<GetMyProjectCharges xmlns="http://COMPANY.IWWeb.Data.Service.ProjectCharges">
<Employee>[string?]</Employee>
<FiscalYear>[string?]</FiscalYear>
<ApiKey>[string?]</ApiKey>
<AppName>[string?]</AppName>
</GetMyProjectCharges>
</Body>
</Envelope>
Next I've gone through some various tutorial as how to build a soap envelop in java but i keep getting into a strange situation where i'm getting <SOAP-ENV: prefixes on everything and when i take the generated envelop and try to paste it into the chrome plugin it doesn't work.
So I'm wondering where I go from here? I realize soap is a pretty heavy protocol and so maybe that is what is confusing me but what I'm looking to do (for now) is:
1) Generate a soap request in java that matches the format above, and print out the results.
I understand i "might" have the option of Maven or some program to generate some class files for me from the WDSL but I'm not exactly sure what i do with that either. Thanks!
Any help would be appreciated.
You have two way to do a soap request.
Solution 1
If you use netbeans as code IDE, you have to create a project, right click on a package and choose New >> Web Service Client. Insert the url of the soap endpoint and click ok. If you have jax-ws/Metro extension installed in your ide netbeans will generate all necessary classes to invoke the service programmatically. (ask me if you have troubles)
Solution 2
you could realize a soap request using simply javax.xml
private SOAPMessage invoke(QName serviceName, QName portName,
String soapActionUri) throws Exception {
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
Dispatch dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
dispatch.getRequestContext().put(Dispatch.SOAPACTION_USE_PROPERTY, new Boolean(true));
dispatch.getRequestContext().put(Dispatch.SOAPACTION_URI_PROPERTY, soapActionUri);
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
Source source = new DOMSource(getQueryString());
soapPart.setContent(source);
message.saveChanges();
System.out.println(message.getSOAPBody().getFirstChild().getTextContent());
SOAPMessage response = (SOAPMessage) dispatch.invoke(message);
return response;
}
private Node getQueryString() throws SAXException, IOException, ParserConfigurationException {
StringBuilder builder = new StringBuilder();
builder.append("<soapenv:Envelope");
// create your body
builder.append("</soapenv:Body>");
builder.append("</soapenv:Envelope>");
DocumentBuilderFactory docfactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docbuilder = docfactory.newDocumentBuilder();
Document stringDocument = docbuilder.parse(new InputSource(new StringReader(builder.toString())));
return stringDocument;
}
and to call the service use
String targetNameSpace = "your target namespace";
QName serviceName = new QName(targetNameSpace, "your service name");
QName portName = new QName(targetNameSpace, "Your port name");
String SOAPAction = "your soap action";
SOAPMessage response = invoke(serviceName, portName, SOAPAction);
if (response.getSOAPBody().hasFault()) {
System.out.println(response.getSOAPBody().getFault());
}
P.S. forgive me for my english :(
I am not sure if I got the point. Anyway I think you need to have the correct namespace for your soap messages. A blank SOAP message would look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
</soapenv:Body>
</soapenv:Envelope>
So in your case I think this should work:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<GetMyProjectCharges xmlns="http://COMPANY.IWWeb.Data.Service.ProjectCharges">
<Employee>[string?]</Employee>
<FiscalYear>[string?]</FiscalYear>
<ApiKey>[string?]</ApiKey>
<AppName>[string?]</AppName>
</GetMyProjectCharges>
</soapenv:Body>
</soapenv:Envelope>
But normally you use a namespace in the payload as well (which means GetMyProjectCharges would be something like jeef:GetMyProjectCharges).
Watch the 2nd namespace in the root tag
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:jeef="http://COMPANY.IWWeb.Data.Service.ProjectCharges">
<soapenv:Header/>
<soapenv:Body>
<jeef:GetMyProjectCharges>
<jeef:Employee>[string?]</jeef:Employee>
<jeef:FiscalYear>[string?]</jeef:FiscalYear>
<jeef:ApiKey>[string?]</jeef:ApiKey>
<AppName>[string?]</jeef:AppName>
</jeef:GetMyProjectCharges>
</soapenv:Body>
</soapenv:Envelope>
To parse the SOAP messages it would be a good choice to use some wsdl to objects conversion tool. There are maven plugins for this as you already found out. To process the SOAP messages it would be worth to take a look at Apache Camel.
Note: namespaces are defined by xmlns:whatever="http://some.url.to.a.model/".
#Jeff you have to do something like this :
MyWebService service = new MyWebService(new Url(wsdlStringEndpoint));
Port port = service.getHttpsoap11port();
port.makerequest();
I've wroted a genericall call to make you understand how it should look. If you have some problems ask again (the code is a sample code)
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.