Handling binary data with SOAP - java

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

Related

what should we use SOAP and when should use REST?

When should we use SOAP and when should we use REST?
Can someone give a justifiable answer to this.
This was asked during an interview. I said it's up to contract with other parties. I don't know whether this is right or wrong. Can someone help with this.
SOAP I mean structure like below.
<?xml version='1.0' Encoding='UTF-8' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<m:reservation xmlns:m="http://travelcompany.example.org/reservation"
env:role="http://www.w3.org/2003/05/soap-envelope/role/next">
<m:reference>uuid:093a2da1-q345-739r-ba5d-pqff98fe8j7d</m:reference>
<m:dateAndTime>2007-11-29T13:20:00.000-05:00</m:dateAndTime>
</m:reservation>
<n:passenger xmlns:n="http://mycompany.example.com/employees"
env:role="http://www.w3.org/2003/05/soap-envelope/role/next">
<n:name>Fred Bloggs</n:name>
</n:passenger>
</env:Header>
<env:Body>
<p:itinerary xmlns:p="http://travelcompany.example.org/reservation/travel">
<p:departure>
<p:departing>New York</p:departing>
<p:arriving>Los Angeles</p:arriving>
<p:departureDate>2007-12-14</p:departureDate>
<p:departureTime>late afternoon</p:departureTime>
<p:seatPreference>aisle</p:seatPreference>
</p:departure>
<p:return>
<p:departing>Los Angeles</p:departing>
<p:arriving>New York</p:arriving>
<p:departureDate>2007-12-20</p:departureDate>
<p:departureTime>mid-morning</p:departureTime>
<p:seatPreference></p:seatPreference>
</p:return>
</p:itinerary>
</env:Body>
</env:Envelope>
In very few words, using REST you can describe the same operations you may expect from a database find, insert, update, delete. In REST such operation are paired with the HTTP command: GET, PUT, POST, DELETE. That's also why REST is referred as "state transfer" in the sense that you move objects in/out like in a database, in other words changing the state of your "model".
On the other hand SOAP reflect more a Remote Call Procedure (RPC) where, the message is heavily structured by XML, this means that in SOAP you do not simple transfer data but submit commands. In SOAP you can define, like in a programming language, methods and parameters. Regarding this last point to allow a client to use the "methods" (really are well structured XML messages, with name and parameters) defined by a SOAP service, the same service has to publish an XML document describing what messages and their format it can accept: if the method does not exists, it throws an error like "Service not supported".

How to convert SOAP XML to Java Object in android

I want parse and convert the SOAP XML response to JAVA objects.
I thought of using J-WS and JAXB to do the same by creating the client stub code. But J-WS and JAXB are not part of Android AOSP hence I have to do it manually.
Following is the example of soap xml response.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
<SOAP-ENV:Body>
<tds:GetSystemDateAndTime/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Response to device.GetSystemDateAndTime
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:tds="http://www.onvif.org/ver10/device/wsdl">
<SOAP-ENV:Body>
<tds:GetSystemDateAndTimeResponse>
<tds:SystemDateAndTime>
<tt:DateTimeType>NTP</tt:DateTimeType>
<tt:DaylightSavings>true</tt:DaylightSavings>
<tt:TimeZone>
<tt:TZ>CET-1CEST,M3.5.0,M10.5.0</tt:TZ>
</tt:TimeZone>
<tt:UTCDateTime>
<tt:Time>
<tt:Hour>15</tt:Hour>
<tt:Minute>52</tt:Minute>
<tt:Second>25</tt:Second>
</tt:Time>
<tt:Date>
<tt:Year>2010</tt:Year>
<tt:Month>10</tt:Month>
<tt:Day>29</tt:Day>
</tt:Date>
</tt:UTCDateTime>
<tt:LocalDateTime>
<tt:Time>
<tt:Hour>17</tt:Hour>
<tt:Minute>52</tt:Minute>
<tt:Second>25</tt:Second>
</tt:Time>
<tt:Date>
<tt:Year>2010</tt:Year>
<tt:Month>10</tt:Month>
<tt:Day>29</tt:Day>
</tt:Date>
</tt:LocalDateTime>
</tds:SystemDateAndTime>
</tds:GetSystemDateAndTimeResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
We can use 3rd party SimpleXML framework which uses Apache 2.0license.
For detailed info & examples, refer the below link -
http://simple.sourceforge.net/
Instead of doing it by hand, you should generate the conversion code by using a tool able to understand the wsdl files with the ONVIF specifications.
Since you are talking about java and android, probably you should check ksoap2-android. I am not an expert of java, but there are some examples available, such this one.

Apache CXF mustUnderstand boolean vs integer

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.

Mechanical Turk rejects POST Requests

I'm trying to use the MTurk restful API, and POST to createHIT with a HITTypeID, however, I get the following error:
<?xml version="1.0"?>
<CreateHITResponse>
<OperationRequest>
<RequestId>199c9aff-86a4-4280-8d2f-d956a53515b0</RequestId>
</OperationRequest>
<HIT>
<Request>
<IsValid>False</IsValid>
<Errors>
<Error>
<Code>AWS.MissingParameters</Code>
<Message>Your request is missing required parameters. Required parameters include Question. Question is a required parameter. (1376962818123)</Message>
<Data>
<Key>Parameter</Key>
<Value>Question</Value>
</Data>
<Data>
<Key>Description</Key>
<Value>Question is a required parameter</Value>
</Data>
<Data>
<Key>Description</Key>
<Value>Question is a required parameter</Value>
</Data>
<Data>
<Key>Parameter</Key>
<Value>Question</Value>
</Data>
</Error>
</Errors>
</Request>
</HIT>
</CreateHITResponse>
From my understanding, title should not be required if Hittype is given. So it looks like the API is not actually viewing the POST body.
How would I work around this? Is there anything wrong with my request?
Request:
<CreateHITRequest>
<HITTypeId>HITTYPEID</HITTypeId>
<MaxAssignments>1</MaxAssignments>
<LifetimeInSeconds>604800</LifetimeInSeconds>
<Question><QuestionForm Structure></Question>
</CreateHITRequest>
You can't POST XML to Mechanical Turk over REST. It looks like you're confusing REST with SOAP to me.
Mechanical Turk's REST interface only takes URL-encoded key-value pairs, like this:
https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester
&AWSAccessKeyId=[the Requester's Access Key ID]
&Version=2012-03-25
&Operation=CreateHIT
&Signature=[signature for this request]
&Timestamp=[your system's local time]
&HITTypeId=T100CN9P324W00EXAMPLE
&Question=[URL-encoded question data]
&LifetimeInSeconds=604800
I had mixed up the POST requests parameters.
For MTURK REST API, you do not POST the XML structure, but headers+values to the indicated URL.
Instead of URL params, you POST them as params in the POST body.
For example the GET request below:
GET https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester
&AWSAccessKeyId=[the Requester's Access Key ID]
&Version=2012-03-25
&Operation=CreateHIT
&Signature=[signature for this request]
&Timestamp=[your system's local time]
&HITTypeId=T100CN9P324W00EXAMPLE
&Question=[URL-encoded question data]
&LifetimeInSeconds=604800
Would become:
POST https://mechanicalturk.amazonaws.com/?Service=AWSMechanicalTurkRequester
AWSAccessKeyId=[the Requester's Access Key ID]
&Version=2012-03-25
&Operation=CreateHIT
&Signature=[signature for this request]
&Timestamp=[your system's local time]
&HITTypeId=T100CN9P324W00EXAMPLE
&Question=[URL-encoded question data]
&LifetimeInSeconds=604800
Where everything below the URL is the POST body.
Hope this helps somebody.

Error while XML parsing with JDOM - Content not allowed in prolog

I get this error while parsing an xml file using JDOM.
What is happening is, I receive a stream of data which is an xml combined with a pdf as an attachment within it. So when I try to create a document of it, this error is thrown.
I tried to print this stream and on the console I get the following, It is with lot of junk chars(the pdf contents) but in Wordpad it looks like -
------=_Part_2_23286828.1296553488632
Content-Type: text/xml; charset=utf-8
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
....
....
....
<Attachment>
<URI>Filename.pdf</URI>
</Attachment>
</SOAP-ENV:Envelope>
------=_Part_2_23286828.1296553488632
Content-Type: application/pdf; name="Filename.pdf"
Content-Transfer-Encoding: binary
Content-ID: </Attachment[1]/URI[1]>
Content-Disposition: attachment; filename="Filename.pdf"
%PDF-1.4
%âãÏÓ
4 0 obj <</Type/XObject/ColorSpace/DeviceRGB/Subtype/Image/BitsPerComponent 8/Width 579/Length 52722/Height 480/Filter/DCTDecode>>stream
ÿØÿà
Please note that the xml between <SOAP-ENV:Envelope> and </SOAP-ENV:Envelope> is well-formed.
How could I go about and create a JDOM document out of it? I guess, by removing the content before and after the xml start/end tags but how in a clean way?
I read that BOMInputStream from Apache IO Commons is helpful but I believe it is in version 2.* and I am using version 1.3.1
I hope this explains my problem, if not pls let me know.
Thank you.
UPDATE
At first I didnt realize it would be this cumbersome.
Actually, I am making a call from one servlet to another(doPost) using HttpURLConnection. The return is in the form of this stream.
Now, I am also trying to explore if in any way I can extract the xml part using some of the methods provided by Http/URLConnection.
Appreciate if anyone could shed some more light on this.
This message conforms to the SOAP with Attachment specification (http://www.w3.org/TR/SOAP-attachments). In java the way to parse these messages is to use an implementation of the SAAJ (Soap with Attachments API for Java: http://download.oracle.com/javaee/5/tutorial/doc/bnbhf.html.) There are a couple of different implementations of SAAJ out there. My personal favorite is the Spring-WS implementation another option is Apache Axiom.
My suggestion to you would be use either Spring-WS or Apache Axis to process this message rather than trying to do it manually from an input stream. Are you trying to do this on the server side or on the client side?

Categories

Resources