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">
<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>
Its pretty hard to spot the difference, but the trick is that all & are replaced with & 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 &
Related
I'm trying to generate an xml payload with jax-ws and it's not working out. The server expects all namespaces to be in the envelope tag. For example:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns2="http://somewhere.namespace2.com">
is what I need, while
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
is what I have.
jax-ws generates a payload like
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns1:Element1 xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns1="http://somewhere.namespace2.com">
<ns2:Element2>value</ns2:Element2>
</ns1:Element1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
but I need
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://somewhere.namespace1.com" xmlns:ns2="http://somewhere.namespace2.com">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns1:Element1>
<ns2:Element2>value</ns2:Element2>
</ns1:Element1>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I have tried putting package-info.java files with the #javax.xml.bind.annotation.XmlSchema and I'm able to change the prefix but not move the actual namespace declaration from a child node to the root node. For example, I can (apparently?) define all the namespaces I need in the envelope with
#javax.xml.bind.annotation.XmlSchema(
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(
prefix = "ns1",
namespaceURI="http://somewhere.namespace1.com"),
#XmlNs(
prefix = "ns2",
namespaceURI="http://somewhere.namespace2.com"),
}
)
But then in the package-info.java where Element1.java and Element2.java are, I don't want the namespaces defined there. I've tried
#javax.xml.bind.annotation.XmlSchema(
namespace="http://schemas.xmlsoap.org/soap/envelope/",
location = ""
)
but it doesn't work.
Has anyone else had a similar problem? I'm sure it's just a question of annotations but I haven't been able to figure it out.
I solved this problem by making the call with Spring's WebServiceTemplate#sendAndReceive(String, WebServiceMessageCallback, WebServiceMessageExtractor<T>) where in the second parameter (the callback) I manually added the namespaces that I needed to be in the header. For example something like
wsResponse = this.webServiceTemplate.sendAndReceive(uri,
(webServiceMessage) -> {
...
SoapMessage soapMessage = (SoapMessage) webServiceMessage;
...
final SoapEnvelope envelope = soapMessage.getEnvelope();
headerNamespaces.forEach(envelope::addNamespaceDeclaration);
...
}, this.responseExtractor);
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();
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)
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.
I'm using a endpoint SOAP created On Spring Framework using JAXB, but I want that my anwers(Expected Response) return without prefix when I Send Request One, but this is returned like is showed on Current Response:.
How can I do to return a message SOAP without namespaces?
Request One
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:sap-com:document:sap:soap:functions:mc-style">
<soapenv:Header/>
<soapenv:Body>
<urn:ZProveerDatosPagoProveed2>
<Bukrs>RG10</Bukrs>
<Langu>S</Langu>
<Lifnr>00000000</Lifnr>
</urn:ZProveerDatosPagoProveed2>
</soapenv:Body>
</soapenv:Envelope>
Current Response:
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<n0:ZProveerDatosPagoProveed2Response xmlns:n0="urn:sap-com:document:sap:soap:functions:mc-style">
<Adrnr>0000</Adrnr>
<Bankk>0000</Bankk>
<Bankn>0000</Bankn>
<Bkont>0000</Bkont>
<Iban>ES0000</Iban>
<KoinhFi>ROBLES AVN</KoinhFi>
<Land1>TH</Land1>
<Landx>XXXXX</Landx>
<Name1>ROBLES AVN</Name1>
<Pstlz>0000</Pstlz>
<Stcd1>A0000</Stcd1>
<Stras>ROBLES AVN</Stras>
<Swift>XXXXX</Swift>
<Text1_052>ROBLES AVN</Text1_052>
<Zterm>Z000</Zterm>
</n0:ZProveerDatosPagoProveed2Response>
</soap-env:Body>
</soap-env:Envelope>
Request one and the current response, are the request/response of a web service embedded in another web service (which I implemented), the reason for this implementation is that it has requested that the final answer is this (without namespaces tags):
Expected Response
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Header/>
<soap-env:Body>
<ZProveerDatosPagoProveed2Response xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Adrnr>0000</Adrnr>
<Bankk>0000</Bankk>
<Bankn>0000</Bankn>
<Bkont>0000</Bkont>
<Iban>ES0000</Iban>
<KoinhFi>ROBLES AVN</KoinhFi>
<Land1>TH</Land1>
<Landx>XXXXX</Landx>
<Name1>ROBLES AVN</Name1>
<Pstlz>0000</Pstlz>
<Stcd1>A0000</Stcd1>
<Stras>ROBLES AVN</Stras>
<Swift>XXXXX</Swift>
<Text1_052>ROBLES AVN</Text1_052>
<Zterm>Z000</Zterm>
</ZProveerDatosPagoProveed2Response>
</soap-env:Body>
</soap-env:Envelope>
The way I was able to do it is the following:
Include the two following jars from JAXB : jaxb-core.jar and jaxb-impl.jar
In the package-info.java file, set the following settings:
Supposing your namespace is "yournamespace"
#javax.xml.bind.annotation.XmlSchema(namespace = yournamespace,
xmlns = {#javax.xml.bind.annotation.XmlNs(prefix = "",
namespaceURI = yournamespace)},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
attributeFormDefault = javax.xml.bind.annotation.XmlNsForm.UNSET)
package com.ctpayment.admin;
It seems that the current implementation of java ignore the previous settings but the jaxb jars do not. I did not push my investigation further. Last but not least, you need the two jars in order to compile.