Using MTOM and Apache FOP with SOAP Web Services
This blog entry builds off the WSDL-first DoubleIt tutorial to demonstrate the Message Transmission Optimization Mechanism (MTOM) for sending and receiving PDF files via
uploadPDF (client->web service provider) and
downloadPDF (WSP->client) SOAP operations. While
uploadPDF just sends a static PDF file to the WSP, the downloadPDF operation dynamically constructs a PDF containing the results of doubling the number sent in the SOAP request. The finished tutorial source code can be obtained from GitHub by using either the "Clone or Download" button or
git clone -v git://github.com/gmazza/blog-samples.git command.
Technologies highlighted in this sample:
MTOM using XML-binary Optimized Packaging (XOP) - MTOM commonly refers to the process of taking base64Binary data within a SOAP message and storing it in an optimized binary format as a MIME attachment. The MTOM Recommendation, however, mostly provides references to the XOP Recommendation where this process is actually defined. Apache CXF has an MTOM documentation page, also the IBM WebSphere App Server documentation provides another good resource.
Apache FOP - FOP is an XSL processor that takes XML documents and generates PDF documents from them (it can generate other output formats as well.) XSL is most commonly used when you want to maintain different output formats for the same source document, such as when using Docbook to output to HTML and PDF. In our example below, the web service provider will use FOP to generate the PDF.
XSLT - XSLT will be used to take the incoming integer from the SOAP request and place the doubled value of it in an XML document that has the XSL tags used by FOP to generate the PDF. Although the stylesheet I'm providing is minimal, FOP allows you to get quite detailed and artistic, and there are also commercial XSL processors such as RenderX and AntennaHouse with different and frequently better capabilities.
Please refer back to the WSDL-first tutorial for this task, as the steps below list just the changes needed in that tutorial to support PDF document transmission.
In Step #2, add the below dependencies element to the service/pom.xml file so the web service provider will have access to FOP and JavaMail. We're including the Mail API dependency because of a helpful ByteArrayDataSource class it provides.
<dependencies> <dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>fop</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.mail</groupId> <artifactId>javax.mail-api</artifactId> <version>1.5.6</version> </dependency> </dependencies>
Also in this step, create the XSLT file for formatting the PDF document. Call it DoubleIt.xsl and place it in the service submodule's src/main/
For Step #3, use the below DoubleIt.wsdl instead. Note the generic
application/octet-stream expectedContentType suitable for transferring PDF documents being used in the downloadPDF request and uploadPDF response which involve transferring a PDF.
For Step #6, use this Web Service Provider instead to return the PDF document.
For Step #8, replace the WSClient with the one below. It receives PDF documents (here's a sample) and saves it to the directory you ran the client from. It then uploads an already existing PDF located in its Maven resources folder.
A packet sniffer such as Wireshark can show MTOM in operation. A CXF SOAP response to a download request from the client is shown below. The PDF document is in its own MIME attachment in an optimized binary format and referenced back to the SOAP message by way of an xop:Include element that holds the PDF's MIME Content-ID value.
HTTP/1.1 200 Content-Type: multipart/related; type="application/xop+xml"; boundary="uuid:4b9b1267-c8e8-458c-aed5-eed03c5c2373"; start="<email@example.com>"; start-info="text/xml" Content-Length: 5987 Date: Sat, 13 May 2017 10:48:29 GMT --uuid:4b9b1267-c8e8-458c-aed5-eed03c5c2373 Content-Type: application/xop+xml; charset=UTF-8; type="text/xml" Content-Transfer-Encoding: binary Content-ID: <firstname.lastname@example.org> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <ns2:DownloadPDFResponse xmlns:ns2="http://www.example.org/schema/DoubleIt"> <doubledNumber> <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:email@example.com"/> </doubledNumber> </ns2:DownloadPDFResponse> </soap:Body> </soap:Envelope> --uuid:4b9b1267-c8e8-458c-aed5-eed03c5c2373 Content-Type: application/pdf Content-Transfer-Encoding: binary Content-ID: <firstname.lastname@example.org> %PDF-1.4 %.... 1 0 obj << /Creator (Apache FOP Version 2.2) /Producer (Apache FOP Version 2.2) /CreationDate (D:20170513064829-04'00') >> endobj 2 0 obj << /N 3 /Length 3 0 R /Filter /FlateDecode >> stream ...rest of PDF attachment...
The web service provider in this example takes the input number and makes a small XML document out of it prior to processing it with the DoubleIt.xsl file. As an alternative processing method, since the SOAP request is itself XML, you can have the web service provider implement the Provider interface and feed the raw SOAP request directly to the DoubleIt.xsl file. See the CXF documentation for further information.
Colm O hEigeartaigh has a blog post on using WS-Security with MTOM.