Foo Infusion

A periodic infusion of foo from the world of a junior developer

Thursday, April 30, 2009

SOAP 1.2 + MTOM + WSE3 + NetBeans WebServices

For a project I'm working on at work right now, I needed to get a web service client implemented using WSE3 and communicating with a web service returning SOAP 1.2 using MTOM.

I know that's a bit of a mouthfull. I'll try to expand those terms a bit.

SOAP 1.2 - just a new version of the SOAP standard. It seems most tools use SOAP 1.1 as the 'standard' version of the standard. The trick seems to be how to tell your tools/technology that you want to use the new SOAP 1.2 standard. I think in reality the syntax of a SOAP 1.1 vs SOAP 1.2 message are pretty similar upon first/shallow glance. While there are some big differences in the model, the REALLY big difference from an implementation point of view seems to be the namespace it uses.

WSE3 - Microsoft's Web Services Extensions, version 3. An updated (and very changed from v.2) version of Microsoft's framework for dealing with web services.

MTOM - Message Transmission Optimization Mechanism - A standard (newish) for transmitting binary data using web services. Using just plain-old web services is not really sufficient for tranmitting binary data because SOAP is an XML standard, and it's difficult to get binary data in XML properly, esp without specialized processing on either end. Essentially, MTOM transmits your SOAP message as a multipart MIME message, with a MIME part for your standard XML SOAP message response, and another separate MIME part for the binary part. The MTOM implementation can unwind that message however it pleases I guess, though it seems that the tools I'm working with seem to take the binary data and Base64 encode it and stick it back in the SOAP XML.

Although I was only implementing the client for my part of the project, I needed a web service that used SOAP 1.2 in order to test that my stuff worked correctly. And I discovered some interesting things while stringing it all together. There didn't seem to be much in the way of help on the interwebs about this, so I wanted to put it up here in case anyone else finds it helpful. (Though I think most people have moved on past WSE3 by now, and are using WCF - I cannot make that move yet, unfortunately).

The soap namespace in your WSDL does need to be changed in order to tell your clients what version of SOAP you want to use:

o SOAP 1.1 : xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
o SOAP 1.2 : xmlns:soap="
http://schemas.xmlsoap.org/wsdl/soap12/"


The correct binding annotation for the SOAP version you wish to use should also be present to tell the JAX-WS stuff how to work. The NetBeans/GlassFish stuff picks SOAP 1.1 by default.(Java 6 has constants for this in the javax.xml.ws.soap.SoapBinding interface - http://java.sun.com/javase/6/docs/api/javax/xml/ws/soap/SOAPBinding.html#SOAP11HTTP_BINDING)
o SOAP 1.1 : @BindingType(value=”http://schemas.xmlsoap.org/wsdl/soap/http”)
o SOAP 1.2 : @BindingType(value="http://java.sun.com/xml/ns/jaxws/2003/05/soap/bindings/HTTP/")
o SOAP 1.1 + MTOM : @BindingType(value=”http://schemas.xmlsoap.org/wsdl/soap/http?mtom=true”)
o SOAP 1.2 + MTOM : @BindingType(value="http://www.w3.org/2003/05/soap/bindings/HTTP/?mtom=true")



MTOM can also be specified by using @MTOM(enabled = true) annotation, but the binding type annotation takes precedence, therefore, specifying the SOAP 1.2 binding type (no MTOM) will give you SOAP 1.2 but NO MTOM even if the @MTOM annotation says otherwise.

The use of MTOM must be specified in the client as well as the WS. If the SoapClient’s RequireMTOM property is set to true, it is expecting a response with a content type of “multipart/related” – if the content type of the response is not “multipart/related” the client will throw an exception while processing the response. If the WS is not using one of the MTOM binding types it will not use a content type of “multipart/related” for the response ( I think it will use “text/xml” instead). So these must match up – if you’re using MTOM (in the WS) you have to tell the client you’re using MTOM so it will expect the “multipart/related” content type in the response, and if you’re not using MTOM you have to tell the client that so it will expect the “text/xml” content type in the response.

Here’s a very basic sample of what the client needs to look like:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Web.Services3.Messaging;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Addressing;

namespace wse3_tester
{

class Program
{

public static String CONTENT_TYPE = "Content-Type";

private String url = "
http://localhost:8888/PDFWebService12/TEIGInquiryService";

private String soapAction = "GetPolicyInquiry";

private String message = @"http://www.teig.com/"">AUTOMyIDEN2003-08-08-03:00";

private bool useMTOM = true;

static void Main(string[] args)
{
Program
p = new Program();

p.test();

}

private void test()
{

SoapEnvelope requestEnv = new
SoapEnvelope(System.Web.Services.Protocols.SoapProtocolVersion.Soap12);

requestEnv.CreateBody();

requestEnv.Body.InnerXml = this.message;

EndpointReference endpoint = new EndpointReference(new Uri(this.url));

WSClient client = new WSClient(endpoint, this.soapAction);

client.RequireMtom = this.useMTOM;

SoapEnvelope responseEnv = client.Send(requestEnv);

}

public class WSClient : SoapClient
{

String methodName;

public WSClient(EndpointReference refr, String methodName) : base(refr)
{

this.methodName = methodName;

}


public SoapEnvelope Send(SoapEnvelope env)
{

return base.SendRequestResponse(this.methodName, env);

}

}

}


And here’s a sample of what the annotations required for the ws:

@BindingType(value="http://www.w3.org/2003/05/soap/bindings/HTTP/?mtom=true")
@WebService(serviceName = "TEIGInquiryService",
portName = "TEIGInquiryPort", endpointInterface =
"com.teig.TEIGInquiryPortType", targetNamespace = "
http://www.teig.com", wsdlLocation =
"WEB-INF/wsdl/TEIGInquiryService12/TEIGInquiry12Wrapper.wsdl")
public class
TEIGInquiryService12 {