From WDSL to java - java

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)

Related

How do I append an XML request to the only SOAPElement child of the SOAP Body?

The use case
I need to contact an external SOAP service in a programmatic way. To do so, I need to create a SOAP request which looks like the below:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pric="http://myURI/">
<soapenv:Header/>
<soapenv:Body>
<pric:myAPI>
<XmlDocument>
<OtherXmlContent>
</OtherXmlContent>
</XmlDocument>
</pric:myAPI>
</soapenv:Body>
</soapenv:Envelope>
The task I'm blocked on
I manage to create the following SOAP envelope:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pric="http://myURI/">
<soapenv:Header/>
<soapenv:Body>
<pric:myAPI>
</pric:myAPI>
</soapenv:Body>
</soapenv:Envelope>
What I need to do, provided an input, is to add the XML request:
<XmlDocument>
<OtherXmlContent>
</OtherXmlContent>
</XmlDocument>
... as a child of <pric:myAPI>, which is the only child of my <soapenv:Body>.
For information, the above Soap envelope (without XmlDocument yet) is created by the following code:
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration(pricingNamespace, pricingNamespaceURI);
SOAPBody soapBody = envelope.getBody();
SOAPElement pricingWrapper = soapBody.addChildElement(pricingAction, pricingNamespace);
... hence, what I need to do is to append a child to pricingWrapper. I choose how I create this child, I have full control on the function generating it which is this one:
private static String createXmlProductFromDealingDocument(Document dealings)
Attempt 1 - adding the document as text
I have tried to add the XmlDocument as text of pricingWrapper.
This is how I did it:
pricingWrapper.addTextNode(createXmlProductFromDealingDocument(dealingFile));
The problem, though, is that all the characters < and > of the XmlDocument rendered as String are escaped by the method addTextNode. In other words, I can see my body has the correct content, but < is replaced with < and > is replaced with >, so making the SOAP request invalid for the target service.
Attempt 2 - adding the document as child node
Another attempt I did was to return a Node instead of a String from my function:
private static Node createXmlProductFromDealingDocument(Document dealings)
and append this Node as a child of pricingWrapper:
pricingWrapper.appendChild(createXmlProductFromDealingDocument(dealingFile));
The above raises an exception of type:
org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
Ok, fair enough. I posted a question (deleted shortly as I wanted to go deeper in my researches) yesterday, and a user kindly suggested me in a comment to check how to clone DOM nodes by referencing this answer.
I tried to do so as follows:
Node pricingRequest = createXmlProductFromDealingDocument(dealingFile);
Node soapPricingRequest = pricingRequest.cloneNode(true);
pricingWrapper.getOwnerDocument().adoptNode(soapPricingRequest);
pricingWrapper.appendChild(soapPricingRequest);
However, this raises a new exception:
org.w3c.dom.DOMException: NOT_SUPPORTED_ERR: The implementation does not support the requested type of object or operation.
... on the following line:
pricingWrapper.getOwnerDocument().adoptNode(soapPricingRequest);
... and I really don't see how else I could append the child differently than what I did above.
What is my question
I just would like to complete my SOAP request the right way. I do not have any preference whether this would be done by injecting the XML as text or as a Node, as far as is the proper way and especially as far as it works :)
Could anyone please tip me how could I fix my above issues?
Reading the javadoc of adoptNode() :
DOMException - NOT_SUPPORTED_ERR: Raised if the source node is of type DOCUMENT, DOCUMENT_TYPE. ".
So, you could you chek if soapPrincingRequest is indeed a DOCUMENT type of node (using getNodeType()) ?
If so, I would advise you to cast soapPrincingRequest as a Document, then access its root NODE with getDocumentElement(), and try to adopt() this NODE, and not the DOCUMENT one.
XML APIs, when they strive for correctness are always a bit touchy to use, and the distinction between a Document and its root element actually matter. So it's a bit of a pain, but we get there in the end.

Send file using Axis2 1.7.4 from java client

I want to send a file using Axis2 1.7.4 to this endpoint https://cel.sri.gob.ec/comprobantes-electronicos-ws/RecepcionComprobantes?wsdl
Part of this code look like this:
OMFactory factory = OMAbstractFactory.getOMFactory();
OMNamespace ns = factory.createOMNamespace("http://ec.gob.sri.ws.recepcion", "RecepcionComprobantesService");
OMElement validarComprobante = factory.createOMElement("validarComprobante", ns);
ConfigurableDataHandler dataHandler = new ConfigurableDataHandler(new FileDataSource("file.xml"));
dataHandler.setTransferEncoding("UTF-8");
dataHandler.setContentType("txt/xml");
OMText textData = factory.createOMText(dataHandler, false);
validarComprobante.addChild(textData);
...
ServiceClient client = new ServiceClient();
...
OMElement response = client.sendReceive(validarComprobante);
I have a response from the server but the file is not accepted, because i get this message"FILES SUBMITTED DO NOT MEET THE SPECIFICATIONS ESTABLISHED: EXTENSION, CODIFICATION"
I read the documentation and the file is sent as Base64 encoded string, so i think that is the problem the content of the file is serialized and i dont know if is possible resolve that.
As per the WSDL description soap request body xml tag expecting base64 encoded string. So you have to read the file content,convert into base64 encoded string and try to pass that string value to xml tag.
You SOAP request should be similar to this
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ec="http://ec.gob.sri.ws.recepcion">
<soapenv:Header/>
<soapenv:Body>
<ec:validarComprobante>
<!--Optional:-->
<xml>VGhpcyBpcyB0ZXN0IGRvY3VtZW50</xml>
</ec:validarComprobante>
</soapenv:Body>
</soapenv:Envelope>

Adding several URIs to SOAP Envelope using Java

I am trying to write a SOAP pull. I am running into difficulty formatting the message correctly.
I am only using the included javax.xml.soap.* library with Exclipse
I need the Envelope to have multiple URIs in it. This is the example provided for use with SOAPUI.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sh="http://www.website.com/ems/soap/sh" xmlns:user="http://www.website.com/ems/soap/sh/userdata" xmlns:ser="http://www.website.com/ems/soap/sh/servicedata">
However after looking through several tutorials I am only able to produce
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sh="http://www.website.com/ems/soap/sh">
I have haven't been able to find any documentation on how to achieve the required output. I am still new to SOAP and Java so I am not sure how to articulate exactly what I need.
Here is the code I have so far minus the child element portion
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
soapMessage.getSOAPPart().getEnvelope().setPrefix("soapenv");
soapMessage.getSOAPPart().getEnvelope().removeNamespaceDeclaration("SOAP-ENV");
soapMessage.getSOAPBody().setPrefix("soapenv");
soapMessage.getSOAPHeader().setPrefix("soapenv");
String serverURI = "http://www.website.com/ems/soap/sh";
// SOAP Envelope
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("sh", serverURI );
If you want to get this soap-envelope,
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sh="http://www.website.com/ems/soap/sh" xmlns:user="http://www.website.com/ems/soap/sh/userdata" xmlns:ser="http://www.website.com/ems/soap/sh/servicedata">
Just add addNamespaceDeclaration after your code like this.
SOAPEnvelope envelope = soapPart.getEnvelope();
envelope.addNamespaceDeclaration("sh", serverURI );
//added code here
envelope.addNamespaceDeclaration("user", "http://www.website.com/ems/soap/sh/userdata" );
envelope.addNamespaceDeclaration("ser", "http://www.website.com/ems/soap/sh/servicedata" );

Parsing SOAP request sent from SOAPUI - using Axis2 Servlet

Here's the SOAP request that I am submitting using SOAPUI
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:My namespace="My Package">
<soapenv:Header>
<Username>q</Username>
<Password>q</Password>
</soapenv:Header>
<soapenv:Body>
<Op:Op>
<Op:int>2134</Op:int>
</Op:Op>
</soapenv:Body>
</soapenv:Envelope>
Now I have created a maven project in eclipse and have generated a wsdl file, aar file (for deploying using Tomcat 7) and a jar file from the Java code (java2wsdl). When the request is submitted, the code must authorize the user with credentials provided under the header element. However, I am not able to parse the SOAP request. When I tried parsing with,
SOAPFactory fac = OMAbstractFactory.getSOAP11Factory();
SOAPEnvelope envelope = fac.getDefaultEnvelope();
SOAPHeader header = envelope.getHeader();
SOAPBody body = envelope.getBody();
Iterator it = header.getChildElements();
Iterator bodyIt = body.getChildElements();
while (it.hasNext()) {
OMElement e = (OMElement) it.next();
System.out.println(e.getText().toString());
}
while (bodyIt.hasNext()) {
OMElement e = (OMElement) bodyIt.next();
System.out.println(e.getText().toString());
}
whereby SOAPFactory and other objects are imported from axiom, none of the print statements where executed. So the question is how do I parse this request so that I have the ability to read the header and body?
I apologize if anything is vague; I am still new to Java web services.
From the Javadoc of the SOAPFactory#getDefaultEnvelope() method:
Create a default SOAP envelope with an empty header and an empty body.
So your Java code behaves as expected.

Error getting response from a web service Non-default namespace can not map to empty URI

I'm trying to make a java webservice client. It's a very simple service that receives a String and return another String. I'm testing the service with soapUI and works perfectly but when I try to code it in java it fails.
Here is the code I'm using to call the service
QName QNAME_TYPE_STRING = new QName(nameSpaceURI,"string");
Service service = new Service();
Call call = (Call) service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName(nameSpaceURI, webServiceMethod));
call.addParameter("buil:arg0", XMLType.XSD_STRING, ParameterMode.IN);
call.setReturnType(QNAME_TYPE_STRING, String.class);
String ret = (String) call.invoke(new Object[]{"PARAMETER VALUE"});
The endPoint variable points correctly to the URL of the service, and:
nameSpaceURI = "http://build.response.service/";
webServiceMethod = "buildResponse";
The thing is that the webService gets the parameter correctly but something happens on the response:
Caused by: com.ctc.wstx.exc.WstxParsingException: Non-default namespace can not map to
empty URI (as per Namespace 1.0 # 2) in XML 1.0 documents
at javax.xml.stream.SerializableLocation#6fee8ce6
This is a sample of my request on soapUI
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:buil="http://build.response.service/">
<soapenv:Header/>
<soapenv:Body>
<buil:buildResponse>
<buil:arg0>PARAMETER VALUE</buil:arg0>
</buil:buildResponse>
</soapenv:Body>
</soapenv:Envelope>
And this is a sample of the response on soapUI
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<ns1:buildResponse xmlns:ns1="http://build.response.service/">
<return xmlns="http://build.response.service/">
RESPONSE1,RESPONSE2,RESPONSE3
</return>
</ns1:buildResponse>
</soap:Body>
</soap:Envelope>
¿Ideas? I think this has something to do with the response, but I'm really a novice with webServices (I know... I know... the 21th century...).
Some more information: I'm not authorized to use wsdl2java nor publish the wsdl of the service (it's autogenerated anyway, I have nothing to do with it and it won't change). Sorry about this, I hope can help me despite this limitations.
Thanks!
God... it was so simple, made this little change on the call parameters:
call.addParameter(new QName(nameSpaceURI, "buil:arg0"),XMLType.XSD_STRING,ParameterMode.IN);
call.addParameter(new QName(nameSpaceURI, "return"), XMLType.XSD_STRING, ParameterMode.OUT);
Now it works like a charm, hope this helps someone.

Categories

Resources