Glen Mazza's Weblog

Main | Next page »

https://web-gmazza.rhcloud.com/blog/date/20170521 Sunday May 21, 2017

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/resources folder.

  • 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="<root.message@cxf.apache.org>"; 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: <root.message@cxf.apache.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:401fdf47-b768-495d-82ec-9f9803a08a4c-4@cxf.apache.org"/>
         </doubledNumber>
      </ns2:DownloadPDFResponse>
   </soap:Body>
</soap:Envelope>

--uuid:4b9b1267-c8e8-458c-aed5-eed03c5c2373
Content-Type: application/pdf
Content-Transfer-Encoding: binary
Content-ID: <401fdf47-b768-495d-82ec-9f9803a08a4c-4@cxf.apache.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...

Notes

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.

https://web-gmazza.rhcloud.com/blog/date/20170514 Sunday May 14, 2017

Sending and processing SOAP faults in web service calls

Following a useful article from Oracle on SOAP faults, this entry expands my intro DoubleIt web service to handle both "modeled" faults (those defined in the WSDL via wsdl:fault elements) and "unmodeled" ones (generally, runtime exceptions that get processed as SOAPFaultExceptions by the SOAP client.) The finished source code can be obtained from GitHub by using either the download ZIP button or git clone -v git://github.com/gmazza/blog-samples.git command.

Here, the DoubleIt web service provider has been adjusted to throw separate WSDL-defined exceptions if the client attempts to double odd numbers or the number 316. As these faults are WSDL-defined, the CXF WSDL-to-Java code generation tool activated by the service's pom.xml generates specific exception classes (DoubleOddNumberFault and DoubleNumber316Fault) for these that can be thrown by the WSP and caught by the SOAP client. Further, attempts to double 428 will throw a non-WSDL-defined runtime exception to show how the client receiving a generic SOAPFaultException.

WSDL changes: The modified WSDL contains two new wsdl:messages for the new faults which you can see subsequently referenced in the wsdl:portType and wsdl:binding sections. It's important to note each wsdl:message needs to have a distinct value for its element (here, DoubleOddFault and Double316Fault defined in the wsdl:types section), even though those two elements have identical contents. This is because the SOAP client uses the element name to determine the type of exception being thrown. (As you can see in the second and third SOAP responses at the bottom, the only difference between the two exceptions is the name of this element.) If you attempt to reuse the same element, results will be shaky. Also note that the wsdl:fault definitions in the portType and binding sections are tied together via their name attributes.

Web service provider: The WSP has been updated to throw the two WSDL-defined faults as well as the RuntimeException for disallowed values.

The WAR submodule's cxf-servlet.xml also has a commented-out faultStackTraceEnabled setting that, if activated, results in the server's Java exception stack trace being sent to the client within every SOAP fault returned. It is seldom desired to leak internal data from the WSP to the SOAP client in such manner (and also makes for rather bloated SOAP responses), but the option is available and perhaps useful in some cases where the service and client are being maintained by the same team.

SOAP Client processing faults: Four calls are made, an acceptable call to double 22 and three other calls that will activate exceptions.

Review of SOAP requests and responses for each of the calls: Running the WSP and activating the client as explained in the original tutorial provides the following output from the client:

The number 22 doubled is 44
Odd number fault: Don't double odd numbers!; basic fault text: 11 is an odd number
316 Fault: Don't double 316!; basic fault text: Attempt was made to double 316
SOAPFaultException: Ha ha!  Didn't tell you 428 can't be doubled either!

Below shows the first SOAP request (the other three differ only by the number being doubled) as well as the SOAP responses for each of the four calls.

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
            <numberToDouble>22</numberToDouble>
        </ns2:DoubleIt>
    </soap:Body>
</soap:Envelope>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns2:DoubleItResponse xmlns:ns2="http://www.example.org/schema/DoubleIt">
            <doubledNumber>44</doubledNumber>
        </ns2:DoubleItResponse>
    </soap:Body>
</soap:Envelope>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Server</faultcode>
            <faultstring>Don't double odd numbers!</faultstring>
            <detail>
                <ns2:DoubleOddFault xmlns:ns2="http://www.example.org/schema/DoubleIt">
                    <errorDetails>11 is an odd number</errorDetails>
                </ns2:DoubleOddFault>
            </detail>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Server</faultcode>
            <faultstring>Don't double 316!</faultstring>
            <detail>
                <ns2:Double316Fault xmlns:ns2="http://www.example.org/schema/DoubleIt">
                    <errorDetails>Attempt was made to double 316</errorDetails>
                </ns2:Double316Fault>
            </detail>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <soap:Fault>
            <faultcode>soap:Server</faultcode>
            <faultstring>Ha ha! Didn't tell you 428 can't be doubled either!</faultstring>
        </soap:Fault>
    </soap:Body>
</soap:Envelope>

https://web-gmazza.rhcloud.com/blog/date/20170507 Sunday May 07, 2017

Tracing SOAP calls with Wireshark

Summary: Learn how to use the Wireshark network analyzer to read your SOAP requests and responses over the wire.

[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170430 Sunday April 30, 2017

Using JUnit to test SOAP clients

This tutorial expands on my original web service tutorial to show how to use JUnit to test SOAP clients.

[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170423 Sunday April 23, 2017

Using Message-Layer Encryption to protect UsernameToken credentials

Summary: See how UsernameToken credentials for SOAP requests can be encrypted via message-layer encryption instead of transport-layer SSL.

[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170416 Sunday April 16, 2017

Deploying and Using a CXF Security Token Service (STS)

Summary: In this tutorial we'll be creating a CXF Security Token Service (STS) and show how to access the STS using a CXF web service client (WSC). The client will authenticate with the STS to obtain SAML tokens that will subsequently be used to authenticate/authorize SOAP requests to a CXF web service provider (WSP) that trusts the STS.

[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170409 Sunday April 09, 2017

Using X.509 security with Apache CXF

This article shows how Apache CXF SOAP requests and responses can be encrypted using WS-Security's X.509 Token Profile (mutual certificates).

[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170402 Sunday April 02, 2017

Using UsernameToken security with Apache CXF

Summary: Learn how to use the WS-Security UsernameToken profile with Apache CXF-based web services.[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170326 Sunday March 26, 2017

Activating Transport Layer Security (SSL) for CXF web services

This tutorial shows how to deploy and call a Tomcat-hosted Apache CXF web service that uses SSL.[Read More]

https://web-gmazza.rhcloud.com/blog/date/20170319 Sunday March 19, 2017

Using Apache CXF to access Salesforce Marketing Cloud SOAP API

I've created a SOAP client using Apache CXF 3.1.x and Maven to access Salesforce Marketing Cloud's SOAP Web Services API, in particular the more generic Partner API. Salesforce's CXF sample, while it contains useful examples that go beyond my tutorial, uses the decade-old CXF 2.0.2 with Apache Ant, so I decided to post a more modern sample. The SOAP client in this tutorial creates a DataFolder with two subfolders in Email Studio of your Marketing Cloud account, something simple to confirm ability to make SOAP calls as well as use for starting boilerplate for your own projects. The tutorial source code can be obtained from GitHub by using either the download ZIP button or git clone -v git://github.com/gmazza/blog-samples.git command.

If you're new to SOAP, you may wish to review my intro web service tutorial.

The project has the following submodules, please take note of the changes needed for the code to work in your environment:

  • exacttarget-jaxws - This submodule primarily contains just the ExactTarget WSDL. The pom for this project uses CXF's wsdl-to-java generator to read the WSDL and from that generate the 300+ JAX-WS and JAXB Java classes used for accessing the Salesforce SOAP endpoint. This submodule in turn gets included as a dependency by the other two modules. The sample project does not contain the WSDL, as it is dependent on the instance (S1, S4, S6, S7, etc.) that you're using -- Salesforce support can help you if you're unsure which one. If wishing to run the sample, view the appropriate WSDL link in a browser, save it as text, and place it as "etframework.wsdl" in the src/main/resources folder of this submodule.

  • salesforce-access-lib - This is (the beginnings of) a library you can include in your application to make the Salesforce SOAP API calls, as stated earlier it just creates three data folders. You'll see that most SOAP actions in Salesforce involve repetitive configuration calls (for example, creating a DataFolder requires specifying several properties for it before saving) so that's it advantageous to factor out this configuration into service methods that you can efficiently call as needed.

  • testapp - This is a simple command-line application that calls a method in salesforce-access-lib to create the data folder. It uses Spring configuration to handle the UsernameToken (username and password) security requirements. To run the testapp:

    • You'll need to know the MID (Member ID) of the Business Unit of your Salesforce instance that you wish to have the SOAP client access, usually (?) a 7-digit number. That can normally be found in the upper-right portion of Email Studio, in the Business Unit dropdown, or contact Salesforce for this information. This value needs to go in the specified location in the testapp's pom.xml where it is read while running the application.
    • You'll need to populate the included creds.properties file with your Salesforce login and password while running the testapp. If you include this project in your own source control, for security you will probably want to exclude this file from your repo (for example, can use a .gitignore file to block its saving if you're using a Git-based version control system.)

After you've made the above-specified modifications, from the root folder run the Maven mvn clean install from a command-line prompt to build all the submodules. You may then navigate to the testapp folder and run mvn exec:exec to run the testapp and create the sample data folders that you'll be able to see once you log into Email Studio (Contents -> My Emails section). They can be deleted by right-clicking on them within Email Studio.

For further help on accessing the SOAP API and working with its objects and methods the Salesforce StackExchange is a good place to post questions.


Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.