Glen Mazza's Weblog

Main | Next page »

https://web-gmazza.rhcloud.com/blog/date/20170611 Sunday June 11, 2017

Switching from SOAP 1.1 to SOAP 1.2 messages

This blog entry shows the steps needed to switch from SOAP 1.1 to SOAP 1.2 formatted messages in your SOAP requests and responses. I'll be showing the modifications necessary for the basic web service tutorial.

The SOAP 1.2 specification is the default SOAP binding for WSDL 2.0, but for the majority of us remaining with WSDL 1.1 the W3C created a reference document to show how SOAP 1.2 messages can defined within WSDL 1.1-based WSDLs. Perhaps the biggest reason to switch to SOAP 1.2 is to take advantage of its enhanced fault code handling. Thankfully, as long as you're using the standard document/literal binding type there are not many WSDL changes needed in upgrading to SOAP 1.2.

Using Wireshark, let's first see what SOAP 1.1 and SOAP 1.2 messages look like over the wire. For CXF, the web service tutorial generates these SOAP 1.1 requests and responses:

POST /doubleit/services/doubleit HTTP/1.1
Content-Type: text/xml;
charset=UTF-8
Accept: */*
SOAPAction: ""
User-Agent: Apache CXF 2.5.1
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8080
Connection:
keep-alive
Content-Length: 224

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

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type:
text/xml;charset=UTF-8
Content-Length: 238
Date: Fri, 20 Jan 20xx 10:33:25
GMT

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

For SOAP 1.2 with CXF:

POST /doubleit/services/doubleit HTTP/1.1
Content-Type:
application/soap+xml; charset=UTF-8
Accept: */*
User-Agent:
Apache CXF
2.5.1
Cache-Control: no-cache
Pragma: no-cache
Host:
localhost:8080
Connection: keep-alive
Content-Length: 222

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Body>
        <ns2:DoubleIt xmlns:ns2="http://www.example.org/schema/DoubleIt">
            <numberToDouble>10</numberToDouble>
        </ns2:DoubleIt>
    </soap:Body>
</soap:Envelope>

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type:
application/soap+xml;charset=UTF-8
Content-Length: 236
Date: Fri, 20 Jan 20XX 14:14:09 GMT

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
    <soap:Body>
        <ns2:DoubleItResponse xmlns:ns2="http://www.example.org/schema/DoubleIt">
            <doubledNumber>20</doubledNumber>
        </ns2:DoubleItResponse>
    </soap:Body>
</soap:Envelope>

For this simple web service call, the main changes of note between SOAP 1.1 and SOAP 1.2 are a different namespace for the SOAP body elements, different Accept headers in the SOAP request and usage of an action parameter in the Content-Type header in SOAP 1.2 instead of a separate SOAPAction HTTP header.

Converting a WSDL-first web service from SOAP 1.1 to SOAP 1.2. Using the WSDL defined for my DoubleIt tutorial, here are the steps I followed:

  1. Add a soap12 namespace declaration to the top-level wsdl:definitions element. (Also good to remove the older SOAP 1.1 namespace declaration, so errors will be returned in case you overlooked converting some elements to the new namespace.)
    xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
    
  2. In the wsdl:binding section, change the namespace prefix of the soap:binding to soap12:binding. The rest of the declaration can remain as-is.
    <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    

    For each wsdl:binding/wsdl:operation element similarly change the namespace prefix of its soap:operation and soap:body elements:

    <soap12:operation soapAction=""/>
    <soap12:body use="literal"/>
    

    The attributes available for the soap:operation element are explained here for SOAP 1.1 and here for SOAP 1.2. The latter offers a new soapActionRequired attribute to require the action parameter be sent. For my web service, I'm requiring only an empty string to be sent (meaning the web service provider should rely on the SOAP body contents to determine the operation to call), but you may wish to provide URI values in your own WSDLs. One URI naming convention is to concatenate the namespace of the WSDL with the name of the operation (example), so for my DoubleIt operation it would be "http://www.example.org/contract/DoubleIt/DoubleIt".

    Finally, in the wsdl:service/wsdl:port section, update the namespace prefix of the soap:address element:

    <soap12:address location="http://localhost:8080..."/>
    
  3. No change to the build process is necessary as the CXF WSDL2Java Maven plugin will detect the new SOAP bindings in the WSDL and generate a SOAP 1.2-compliant web service provider and client accordingly.

Converting a Java-first web service from SOAP 1.1 to SOAP 1.2.

  1. Add the SOAP12HTTP_BINDING annotation to your web service implementation class:

    import javax.xml.ws.BindingType;
    
    @WebService(targetNamespace = "http://www.example.org/contract/DoubleIt",
                ...)
    @BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
    public class MyJavaFirstPortTypeImpl implements MyJavaFirstPortType {
    ...
    
  2. That's it. You can build/deploy the web service and client as usual. Note that CXF's Maven Java2WS plugin has a <soap12/> setting but using it appears to have no practical effect--while it will generate a SOAP 1.2 WSDL locally, unless the @BindingType annotation above is set it will still deploy as a SOAP 1.1 web service. Further, the annotation above alone is sufficient for CXF to deploy a SOAP 1.2-based web service.

https://web-gmazza.rhcloud.com/blog/date/20170609 Friday June 09, 2017

New OSHA regulation needed?

Today for the first time I visited Old Fort Niagara located in Niagara County, New York State, where the Niagara River and Lake Ontario meet. Beautiful place, fort and scenery amazing, highly recommend. Saw something I didn't like though at the end of my visit -- there is one long and rather steep embankment that Old Fort Niagara maintains as a grassy lawn that apparently receives regular mowing. The embankment was to a degree that the two lawnmowing employees using push mowers seemed to be having trouble mowing it laterally (as gravity would presumably cause a mower to slide down to the bottom), and so I saw them instead push the mower up from the bottom to the top, such as that if they were to slip and lose their balance and fall while pushing it upwards, the unspeakable could happen.

Granted, I only watched for a minute or so before being alarmed, so pushing (well, driving, as it appeared the wheels turned on their own) the mower upwards may not have been the regular procedure that they follow, but just that of a few unfortunate edge cases, but after the second consecutive time seeing one employee do this I signaled my concern to an information guide and we then saw the second employee do the same thing. The guide said he would bring that issue up to management, and to further play it safe I raised my concern separately to two other employees on my way out. Even with dry conditions as we had today that would be questionable, but what if the grass was wet and slippery?

When a organization chooses to maintain a slope that steep, perhaps OSHA should come in and put in some safety regulations for employees asked to mow things such as that. My suggestion would be that any slope that is so steep that a person cannot cut laterally across it needs to be cut with a non-motorized grass cutter instead. Perhaps we can be more specific, saying anything above (say) 45 degrees must be non-motorized. Such a rule will give organizations the option of power mowing below 45 degrees, manual clippers of live grass above 45 degrees, or choosing options that don't require mowing (such as ivy or artificial grass) if they find slopes greater than 45 degrees to be the most attractive but don't wish to deal with any reduced effectiveness of the manual clippers.

The non-motorized tools are perhaps not as good at cutting everything, but any missed grass blade is all but certain to be cut the next time around, meaning one is not going to have stray grass blades several inches longer than others due to them being continually missed. And as for some mechanical mowers leaving the clippings while the real ones pick it up, an argument can be made that that's where they should remain anyway, instead of filling landfills, but even if not they can always be manually raked and collected afterwards. Alternatively, any concerns that it wouldn't be historically accurate for Old Fort Niagara to switch to ivy, well, it's certainly not historically accurate that the grass on those embankments was maintained impeccably either. Ultimately, we're here to see a fort, not oooh and aaah a gorgeously maintained baseball field, and we should be expected to make modern day adjustments for the safety of all.

https://web-gmazza.rhcloud.com/blog/date/20170605 Monday June 05, 2017

TightBlog 2.0 Released!

See the updated homepage README for details. Enjoy!

https://web-gmazza.rhcloud.com/blog/date/20170604 Sunday June 04, 2017

Customizing and enhancing JAXB classes generated during the WSDL-to-Java process

If you're using JAXB databinding for your SOAP services, CXF's wsdl2java tool provides considerable flexibility in customizing the JAXB-generated Java classes, in general, those which map to the SOAP request and response objects. I'll be showing how this configuration can be added using a wsdl2java run on the eBay WSDL (download). (Not covered in this entry, but if you also or alternatively wish to modify the JAX-WS artifacts (i.e., the port and service classes) consult the wsdl2java command-line options and/or use a JAX-WS binding file.) The tutorial source code can be obtained from GitHub by using the "Clone or Download" button on the project site.

Four methods of configuring JAXB are discussed:

  1. Passing arguments to the XJC compiler to modify the generated JAXB artifacts
  2. Using a binding customization file
  3. Using third-party JAXB plugins to expand XJC command-line and binding file options
  4. Creating your own JAXB plugin

For ease of reference the pom.xml holding many of these customizations is shown below:

  1. Passing arguments to the XJC compiler to modify the generated JAXB artifacts

    There are several command-line options that can modify the generated JAXB objects without need for binding files or custom plugins, calling "xjc -help" at a command line that has the Java SDK in the classpath will give provide a complete list. Command-line options include specifying binding customization files, episode files (although they have limitations with wsdl2java), and changing the desired package name (-p) for the generated Java classes (this can also be done with binding files, as will be shown later.) Other options include the ability to add SAX Locator information (-XLocator), the @Generated annotation (-mark-generated) and the synchronized keyword (-Xsync-methods) to the exposed methods of the JAXB classes. You can see this configuration done in the pom.xml above via extraargs elements added to the cxf-codegen-plugin configuration. Note the desired options can either be placed on one line or split into multiple lines.

    Command-line option inheritance: The CXF Maven plugin provides an ability via the defaultOptions element to declare settings common for all WSDLs being processed within submodules. Unfortunately an extraargs or xjcArgs element declared at the WSDL level will override all other XJC settings defined at the higher level, so if you do a WSDL-level override of XJC arguments you will also need to include the non-overridden XJC settings present at the higher level.

  2. Using a binding customization file

    Customization of the XML Schema-to-Java binding process is covered in Chapter 7 of the JAXB 2.2 specification. The binding customization schema (download) provides a formal definition of the allowed customization elements, however JAXB provides extensions that again can be listed via xjc -help via command line. The sample binding file referenced by the cxf-codegen-plugin configuration is below. Note that the #types1 suffix to the jaxb:binding's schemaLocation attribute refers to the 1-based count of the xsd:schema element within the wsdl:types section. The JAXB compiler will usually give a helpful error message if the node syntax is incorrectly given.

    In addition to the JAXB configuration given in the pom.xml, the above binding file will make the following changes to the generated Java classes:

    • Via jaxb:schemaBindings, specifies the Java package that the classes will be a part of. (If not specified, package names derived from the Schema namespaces are used.)
    • Specifies that MyRenamedCatalogProductType will be the generated Java class for element CatalogProductType, and gives the class-level JavaDoc comment to be used for it.
    • Has MyRenamedCatalogProductType implement two interfaces using the third-party JAXB2 Basics's Inheritance Plugin: Cloneable and an empty marker interface I placed in the client package.
    • In class ErrorParameterType, adds a method-level JavaDoc comment for the errorValue property and renames a member variable from the paramID specified in the schema to myParamOverrideID.

    You can inspect the changes made by running mvn clean install on the project and then looking at the generated classes in the target/generated-sources folder.

    Notes:

    • These customizations can also be done in-line within the schema instead of using an external binding file as explained in the Sun Web Services tutorial.
    • An important customization not shown in the above binding file is jaxb:javaType, used in changing the mapping between the schema type and the resulting Java object generated, for example switching from XMLGregorianCalendar to java.util.Date for XML date/time types.
    • There is both a standard jaxb:javaType and a xjc:javaType extension providing additional functionality--see this Core Java Tech Tips article for details on the latter's usage.
    • Stackoverflow has a post on how the JAXB classes can be made serializable for caching or other purposes.

  3. Using third-party JAXB plugins to expand XJC command-line and binding file options

    Third party products such as the CXF XJC Extensions and Aleksei Valikov's JAXB2 Basics allow for additional customizations besides the functionality provided by JAXB, such as adding toString() and hashCode() methods to the generated classes. Mr. Valikov provides a wiki page and sample project for integrating JAXB Basics with CXF. (CXF also provides a JAXB wrapper that allows its plugins to be used for pure databinding--i.e., non-JAX-WS--purposes.) The pom.xml for this sample uses plugins from both these libraries, as explained in its comments. Note in the case of the JAXB2 Basics configuration the need to include the jaxb2-basics dependency within the codegen plugin and also jaxb2-basics-runtime as a compile-scope dependency as the plugin generates references to classes provided by the latter that will be needed when running the client.

  4. Creating your own JAXB plugin

    Checking the source code within the CXF XJC and JAXB2 Basics plugins can provide guidance, in particular the source for any plugins that provide functionality similar to what you are looking for. As with these third party plugins, within the pom.xml you'll probably need to add a new dependency for your plugin to the CXF codegen plugin, and if your plugin generates references to classes that will subsequently be needed at runtime, dependencies to the SOAP client as well.

https://web-gmazza.rhcloud.com/blog/date/20170528 Sunday May 28, 2017

Using SoapUI to make Salesforce Marketing Cloud API calls

This tutorial shows how to make SOAP requests to Salesforce' Marketing Cloud API using the open source version of SmartBear's SoapUI. The feedback that SoapUI provides is very helpful in figuring out the correct SOAP request format for each action desired to run. SOAP request envelopes created within SoapUI can be easily saved for later reuse, allowing you to bypass the sometimes cumbersome Email Studio for often-run actions. Also, knowledge of the correct SOAP requests and SOAP responses returned helps speed up development for accessing the API via programmatic means, for example as shown in my Salesforce/Apache CXF tutorial. As with that tutorial, I'll be demonstrating creation of an email data folder, a simple task that provides an easy way to confirm connectivity and authentication before moving on to more complex activities.

Steps:

  1. Download SoapUI if you haven't already. Free open source version will do.

  2. Import the Marketing Cloud WSDL into a new SoapUI project. Select SoapUI menu item File | New SOAP Project. A New SOAP Project popup will appear (see illustration below.) Choose whatever project name desired. For the Initial WSDL, that can be retrieved from the Salesforce Marketing Cloud (SFMC) WSDL Links page. Choose the WSDL appropriate for the SF instance that you are using: S1, S4, S6, or S7 -- the illustration below shows S1 which may or may not be the correct one for your project. Contact SF customer support if you are uncertain which SFMC instance you are using.

    NewSOAPProject.png

    Good to check "Create Requests" as shown above, although this functionality is less useful here than for other web services. SFMC uses generic SOAP operations like Create and Retrieve that hold for dozens of objects instead of specific ones such as CreateXXX, RetrieveYYY, etc. resulting in unworkably large sample SOAP requests to handle the many objects these methods can be applied to.

  3. Configure Username Token Authentication for the SOAP calls. This need be configured only once for all SOAP calls. SoapUI provides efficient documentation for configuring WS-Security, of which SFMC uses the UsernameToken type. To configure, select menu item Project | Show Project View and select the WS-Security Configurations tab from the resulting popup. The (anonymized) settings below are what I configured for my own calls to work, make sure you also have the configuration as given in the bottom half of the illustration. The "Name" field at the top of the illustration can be whatever you want, it is used to identify the security properties desired for any particular SOAP call. The username and password can be what you use to log into Email Studio or can be a new account used specifically for SOAP calls.

    ConfigureWSS.png
  4. Create the SOAP request envelope. General process:

    1. Clone the sample request provided by SoapUI. Creating a clone allows you customize the sample SOAP call to something specific for your needs, while allowing the sample SOAP call to remain as-is so you can clone it again to perform a different action. To clone, right-click the sample request, select "Clone Request" and give the clone a useful name (say "CreateDataFolder"). You'll see it created next to the original sample request. Double-click the cloned request to bring it up in the editor window.

      CloneRequest.png
    2. Configure the UsernameToken for the call. In the editor window for the CreateDataFolder call, select the Auth button in the lower-left corner, choose Basic Authentication, leave the basic auth username and password blank, and for Outgoing WSS select the name of the UsernameToken authentication you configured earlier (see illustration).

      ConfigureWSSForRequest.png
    3. Check the SFMC documentation to help determine the required SOAP request format for the desired action. For each action, some trial and error can be expected to figure out the correct call. SoapUI excels at providing pre-call validation and rapid SOAP responses helpful for getting the calls right. The best first step is to check the documentation page for the specific SFMC object you're working with, in this case it would be the Data Folder page (note the other objects listed on the left-side menu in case you're working with something else.) You'll get a reasonably accurate listing of properties that can be defined and the types of actions (Create, Retrieve, etc.) permissible on the object. In the case of the Data Folder and some other objects, the bottom of the page gives a link to sample SOAP requests which I've not found to provide everything that's needed but a good starting step. In the case of creating data folders, I've found the description field to be required (or an unclear error response is given), the xmlns:xsi namespace needed to be added to the soap:envelope and a Client element for your project's MemberID needed. You'll also need to determine the ID of the parent folder for the new folder you're creating, one way to obtain this is to hover over the parent directory with the mouse in Email Studio and reading the "cid" value given in the tooltip popup at the bottom of your browser while doing so. The following is the format that worked for me to create the data folder:

      <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:par="http://exacttarget.com/wsdl/partnerAPI">
          <soapenv:Body>
              <par:CreateRequest>
                  <par:Options/>
                  <par:Objects
                          xsi:type="par:DataFolder">
                      <par:Client>
                          <par:ClientID>...yourMID#...</par:ClientID>
                      </par:Client>
                      <par:ModifiedDate xsi:nil="true"/>
                      <par:ObjectID xsi:nil="true"/>
                      <par:ParentFolder>
                          <par:ModifiedDate xsi:nil="true"/>
                          <par:ID>...ParentFolderID#...</par:ID>
                          <par:ObjectID xsi:nil="true"/>
                      </par:ParentFolder>
                      <par:Name>emailFolderViaSoapUI</par:Name>
                      <par:Description>emailFolder1Desc</par:Description>
                      <par:ContentType>email</par:ContentType>
                      <par:IsActive>true</par:IsActive>
                      <par:IsEditable>true</par:IsEditable>
                      <par:AllowChildren>true</par:AllowChildren>
                  </par:Objects>
              </par:CreateRequest>
          </soapenv:Body>
      </soapenv:Envelope>
      
    4. Validate the SOAP request prior to sending it. If the SOAP request is not valid (missing required elements for example), running it will return a "400 Bad Request" message in the response window. These types of errors can normally be trapped beforehand by right-clicking the SOAP request in the editor window and choosing "Validate". Soap UI will return any WSDL or XML Schema validation errors for you to fix.

  5. Make the SOAP call. Clicking the green arrow in the upper-left corner of the editor window is all that is needed. However, even with the validation done earlier, the SOAP response may return an error message indicating further tweaking needed.

    • Check the SOAP response for any useful information. In the case of a create data folder request, you'll receive the "NewID" of the folder you created, which you can use to make further changes to the folder. Below shows the (anonymized) SOAP response to my SOAP request:

      <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" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
          <soap:Header>
              <wsa:Action>CreateResponse</wsa:Action>
              <wsa:MessageID>urn:uuid:xxxxxx</wsa:MessageID>
              <wsa:RelatesTo>urn:uuid:yyyyyy</wsa:RelatesTo>
              <wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
              <wsse:Security>
                  <wsu:Timestamp wsu:Id="Timestamp-zzzzzz">
                      <wsu:Created>2017-05-21T14:19:52Z</wsu:Created>
                      <wsu:Expires>2017-05-21T14:24:52Z</wsu:Expires>
                  </wsu:Timestamp>
              </wsse:Security>
          </soap:Header>
          <soap:Body>
              <CreateResponse xmlns="http://exacttarget.com/wsdl/partnerAPI">
                  <Results>
                      <StatusCode>OK</StatusCode>
                      <StatusMessage>Folder created successfully.</StatusMessage>
                      <OrdinalID>0</OrdinalID>
                      <NewID>012345</NewID>
                      <NewObjectID>zzzzzz</NewObjectID>
                  </Results>
                  <RequestID>wwwwww</RequestID>
                  <OverallStatus>OK</OverallStatus>
              </CreateResponse>
          </soap:Body>
      </soap:Envelope>
      
    • Go into SFMC Email Studio to confirm the folder you created is there. If you had Email Studio already open, may need to refresh once or twice for the folder to appear. Can delete the folder from within the Studio if desired (or create another web service call to do that as well.)

    • Save the project to retain your SOAP request envelopes. Menu item Project | Save Project will do. Keeping this SOAP request template will allow you to tweak and reuse it later to create other folders.

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.

  • Colm O hEigeartaigh has a blog post on using WS-Security with MTOM.

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

Sending and processing SOAP faults in web service calls

Summary: Learn how to send and process different types of SOAP faults during web service calls.[Read More]

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]


Valid HTML! Valid CSS!

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