Apache CXF mustUnderstand boolean vs integer - java

I am working on a soap 1.1 service with Apache CXF 3.1.12 (with springboot)
I am trying to understand how I can coerce it into generating the mustUnderstand header as an integer (0|1) instead of boolean (true|false). See the incorrect document below. From what I understand, in soap 1.1 the true/false is not acceptable. Regardless, my clients do not like it and I do not have control over them.
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="true">http://...</a:Action>
</s:Header>
<s:Body>
...
</s:Body>
</s:Envelope>
This is a WSDL-first service and there is no mention of the SOAP 1.2 namespace in the WSDL. My package info is:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://...", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
and my endpoint is created with:
EndpointImpl endpoint = new EndpointImpl(bus,
new MyClass(), SOAPBinding.SOAP11HTTP_BINDING);
I modify the mustUnderstand header in an AbstractSoapInterceptor at Phase.WRITE with hdr->setMustUnderstand(true), yet it still goes out as a boolean.
There is an old issue in JIRA about this, and is marked as fixed a long time ago: https://issues.apache.org/jira/browse/CXF-2213?jql=text%20~%20%22mustUnderstand%22
Any help would be appreciated.

I managed to fix this by forcing the response to be a SOAP 1.1 response in the interceptor, via:
final SoapVersion soap11 = Soap11.getInstance();
message.setVersion(soap11);
I doubt this is the correct way, I am not sure why it insists in thinking it's not a SOAP 1.1 message. But this at least fixed the specific issue above, and will allow me to proceed until I find the correct way.

Related

CXF TransformOutInterceptor removing SOAP attachments when used

I have a SOAP client and I need to set the default namespace - which I am doing with a TransformOutInterceptor as such:
Map<String, String> outTransformMap = Collections.singletonMap("Test", "Test");
org.apache.cxf.interceptor.transform.TransformOutInterceptor transformOutInterceptor = new org.apache.cxf.interceptor.transform.TransformOutInterceptor();
transformOutInterceptor.setDefaultNamespace("http://test");
transformOutInterceptor.setOutTransformElements(outTransformMap);
ClientProxy.getClient(client).getEndpoint().getOutInterceptors().add(transformOutInterceptor);
This is working fine in terms of changing the default namespace, and the SOAP message is being successfully received and parsed by the server, however, by running the transformation it is removing all the SOAP attachments and changing the Content Type of the message from mime to text/xml.
Can anyone help? Is this a bug or am I missing something? I've tried changing the phases at which the interceptor is run, but with to avail.
Many thanks
Matt

Remove <soapenv:Header> from payload in XML route

I am looking for solution how to remove <soapenv:Header> part from SOAP request using XML-based routing (Apache Camel Blueprint XML).
So this:
<soapenv:Envelope xmlns:net="..." xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
...
</soapenv:Header>
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>
shall become just this:
<soapenv:Envelope xmlns:net="..." xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
...
</soapenv:Body>
</soapenv:Envelope>
I think I found java-based solution, also xslt-based solution, but I dont find them quite suitable for my project, and I still hope there is some simple way how to do it directly in XML route without creating java processing class or adding XSLT template.
I was trying <removeHeaders pattern="_something_"/> but either I cant figure out the correct "something", or this command only applies to headers above payload section...
In Blueprint you can get the body of the XML by using XPATH. Something like this:
<setProperty propertyName="MessageBody">
<xpath>//*[local-name()='Body']</xpath>
</setProperty>
Then you could reconstruct your message with the envelop tag.
<setBody>
<simple><![CDATA[<Envelope>${property.MessageBody}</Envelope>]]></simple>
</setBody>
This will only work if your Envelope tag is a constant.
The easiest way I would thing is to parse the SOAP message and then remove the header. You can do that with SAAJ.
How to remove empty header from SOAP message?
.removeHeaders() is for removing Camel exchange headers which is something completely different.
It depends on what dataformat you are using for the CXF endpoint, Is this SOAP request coming from someother service ?
Why are you not happy with XSLT ?
Regardless, You can remove if you use payload DATAFORMAT.
So I find perfect and very simple solution to my issue:
The contents of <soapenv:Header> (along with contents of <soapenv:Body>) were stored in CxfPayload object , which is part of org.apache.camel.Exchange
After I learned this, I was just one Groovy command, that can be easily included in routes.xml, away from solution:
<groovy>
exchange.getIn().getBody(org.apache.camel.impl.DefaultMessage.class).getBody(org.apache.camel.component.cxf.CxfPayload.class).getHeaders().clear();
</groovy>

Handling binary data with SOAP

I have been investigating how to handle binary data with SOAP messages. I am developing both the client and the service so i have the option of choosing whichever framework. The only constraint is that the Service end has already been designed and is based on Spring-WS.
Looking at google, it looks like there are three options:
Sending the attachment inline as base64 in the SOAP message (Base64Binary).
Sending the attachment outside of the SOAP message. i.e. with a reference to the attachement (SWA)
Sending the attachement outside the message but make it appear as though it is embedded in the message (MTOM).
Questions
What exactly does it mean when they say that the attachement is outside of the SOAP message? I assume that maybe the attachement is sent as a different TCP package but i think i am wrong?
Which of the above options is recommended and specifically, which one works best with Spring's Spring-WS framework?
It is unclear to me which of the above options encode the binary content during transmission. What is Binary MIME as described here - http://www.crosschecknet.com/intro_to_mtom.php ? Is the binary data still converted to text during transmission?
What is the format of the data when using SWA?
What exactly does it mean when they say that the attachement is outside of the SOAP message? I assume that maybe the attachement is sent as a different TCP package but i think i am wrong?
In contrast to the first option the attachment is not part of the actual soap message payload but instead referenced to within the SOAP document. The difference between MTOM and SWA is where the referenced file is located. For MTOM it's embedded in the response, while in SWA you could for example get a link to the resource on the web. It follows 3 minimal examples:
MTOM (all in one response of type xop+xml)
Content-type: multipart/related;
type="application/xop+xml";
start-info="text/xml"
--uuid:c73c9ce8-6e02-40ce-9f68-064e18843428
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary
<?xml version="1.0" ?>
<S:Envelope xmlns:S="...">
<S:Body>
<ns2:downloadImageResponse xmlns:ns2="...">
<return>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
href="cid:012eb00e-9460-407c-b622-1be987fdb2cf#example.jaxws.sun.com">
</xop:Include>
</return>
</ns2:downloadImageResponse>
</S:Body>
</S:Envelope>
--uuid:c73c9ce8-6e02-40ce-9f68-064e18843428
Content-Id: <012eb00e-9460-407c-b622-1be987fdb2cf#example.jaxws.sun.com>
Content-Type: image/png
Content-Transfer-Encoding: binary
SWA (only reference)
Content-Type: application/xml;charset=utf-8;
<?xml version="1.0" ?>
<S:Envelope xmlns:S="...">
<S:Body>
<ns2:downloadImageResponse xmlns:ns2="...">
<return>
https://server.com/downloadImagehere.png
</return>
</ns2:downloadImageResponse>
</S:Body>
</S:Envelope>
Inline
Content-Type: application/xml;charset=utf-8;
<?xml version="1.0" ?>
<S:Envelope xmlns:S="...">
<S:Body>
<ns2:downloadImageResponse xmlns:ns2="...">
<return>
YTM0NZomIz...potentiallyLargeBase64encodedFileGoesInHere...I2OTsmIzM0NTueYQ==
</return>
</ns2:downloadImageResponse>
</S:Body>
</S:Envelope>
Which of the above options is recommended and specifically, which one works best with Spring's Spring-WS framework?
They are all supported, and the one to use depends a bit on your use-case. MTOM seems to be the de-facto standard according to my research. According to me it it's particularly useful if you have either large or multiple file attachements. Since it splits the message in it's logical components it might give the parser more options to handle the binary data efficiently.
However, for smaller data I would probably go for the embedding of the resource, since it's part of the standard SOAP protocol and only uses an encoded byte array directly which is then directly embedded into the message. If portability/compatibility is important this might be the approach to choose.
The last approach obviously requires you to handle the reference by yourself, which might or might not be what you want.
It is unclear to me which of the above options encode the binary content during transmission. What is Binary MIME as described here - http://www.crosschecknet.com/intro_to_mtom.php ? Is the binary data still converted to text during transmission?
MTOM and Inline both encode the file usually as Base64encoded String. For external links it's not relevant.
What is the format of the data when using SWA?
Base64encoded byte array

CXF webservice client, how to handle response from a called webservice?

i have implemented a webservice client that is used inside a webapplication (using Spring) and this client gets a response in which CXF bailsout and gives me an error message.
The error message is:
Server did not recognize the value of HTTP Header SOAPAction
I have found the problem but do not know what i can do to adjust my webservice response handling.
The xml response below works without any problems.
Works and is accepted ok!
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:bar="http://www.dummyurl.com/service-v1.0/">
<soapenv:Header/>
<soapenv:Body>
<bar:StartSessionResponse>
<result>1</result>
</bar:StartSessionResponse>
</soapenv:Body>
</soapenv:Envelope>
The service actually returns:
Fails and gives me an error!
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<StartSessionResponse xmlns="www.dummyurl.com/service-v1.0/">
<result xmlns="">1</result>
</StartSessionResponse>
</soap:Body>
</soap:Envelope>
The difference as far as i can see is in the placing of the
xmlns="www.dummyurl.com/service-v1.0/ element, in the success xml it is in the enveloppe, in the failed xml it is on the reponse method.
Is there a way that i can convince CXF to accept the response? Or is the service giving back an abnormal result?
The service is giving back a wrong response in the second case, assuming that the first response is proper.
In the first case "www.dummyurl.com/service-v1.0/" is the namespace of your elements - StartSessionResponse, result is not qualified with the namespace. In the second case, the StartSessionResponse has the same namespace as the first sample, but the result has a different namespace altogether, taking out xmlns="" for result will make the xml consistent.

WCF client errors when consuming Java services

I'm currently working on a project where I need to consume a Java webservice. If I connect to the service using old webservices (asmx) it works fine. However, If I try to do the same thing with a WCF client I get the following error:
The content type text/xml; charset=utf-8 of the response message does not match the content type of the binding (application/soap+xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly.
My is very simple and it looks like the following:
//classic web service
OldSkoolService.HelloService serviceCall = new esb_wsdlsample.OldSkoolService.HelloService();
Console.WriteLine(serviceCall.SoapVersion);
Console.WriteLine(serviceCall.sayHello("something"));
HelloServiceClient prototypeClient = new HelloServiceClient();
var serviceChannel = prototypeClient.ChannelFactory;
Console.WriteLine(serviceChannel.Endpoint.Binding.MessageVersion);
Console.WriteLine(prototypeClient.sayHello("somethinge")); //<-- Error occurs here
The the binding/endpoint config file is quite simple as well:
<bindings>
<customBinding>
<binding name="Soap12Binding">
<textMessageEncoding messageVersion="Soap12"/>
<httpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://10.10.6.51:7001/esb/HelloService" behaviorConfiguration=""
binding="customBinding" bindingConfiguration="Soap12Binding" contract="Prototype.ESB.HelloService"
name="HelloServicePort" />
</client>
As a side note I'm trying to use soap 1.2, because I need to be able to catch exceptions from the service.
Based on your error message, it simply means that your Server response message is SOAP 1.1, while you expect SOAP 1.2.
You'll have to change to SOAP 1.1 on the client (using BasicHttpBinding, at least do it to test and see if it works that way).
While it isn't required by the SOAP 1.2 specification, it is recommended (i.e. SHOULD) that SOAP messages use a content-type of application/soap+xml.
You should change this on the server side. If not, then I think that you will have to fiddle around with the textMessageEncoding binding element in the config file to make it accept the text/xml content-type.

Categories

Resources