Monday, March 24, 2008

soap with attachments, axis1 and href

Warning: Read on only if these terms together instantly give you a headache or bring you bad memories.

If you use axis in your project (and indeed it hides nicely the details of constructing SOAP messages and lower level APIs like SAAJ) you probably write code like this to invoke a remote service with attachments:
X_BindingStub service =
(X_BindingStub) new X_ServiceLocator().
getY([<url>]);
service.setUsername(<username>);
service.setPassword(<password>);
MyBusinessObject obj = new MyBusinessObject();
obj.setXXX(...);
service.addAttachment(new DataHandler(...
service.remoteMethod(obj);

But it might be that unless your business object (that Axis will serialize into the BODY part of the SOAP message) will reference the attachment, the remote system will simply ignore the attachment, or worse, your entire message.

This linking is not something the Axis guys invented, just something that they made harder to control. See http://www.w3.org/TR/SOAP-attachments for the different ways to link the SOAP message with the attachment within a MIME message.

...and here is how you could do it with Axis while leveraging the classes that wsdl2java generated:
Service service = new Service();
Call call = (org.apache.axis.client.Call)
service.createCall();
// set call endpoint, username, password

// locate the description of the remote method you want
// to call in X_BindingStub and use it here:
OperationDesc oper =
new org.apache.axis.description.OperationDesc();
oper.setName("remoteMethod");
ParameterDesc param ...
...
call.setOperation(oper);

// locate the remote method you want to call in
// X_BindingStub and use that code fragment here:
call.setUseSOAPAction(true);
...
call.setOperationName(new javax.xml.namespace.QName(...

// create the attachment
AttachmentPart ap = new AttachmentPart(new DataHandler(
"All my worries are gone now", "text/plain"));
String contentIdRef = ap.getContentId();

// construct the XML string that the remote function
// expects (it'd be very easy if you could take this from
// the remote service logs). Link to the attachment by
// setting the href attribute of an XML elem. Note that
// the remote method must expect the href attribute on
// the very XML elem where you place it
String xmlString = "<xxx>...href=\""
+ contentIdRef + "\"...</xxx>";

// call the remote service
call.addAttachmentPart(ap);
call.invoke(new Object[] {new SOAPBodyElement(new
ByteArrayInputStream(xmlString.getBytes("UTF-8")))});

It might be that the same works with axis2, your turn to test and let me know. As for MIME and DIME attachment encodings, both work, just use this extra code for DIME attachments:
call.setProperty(
Call.ATTACHMENT_ENCAPSULATION_FORMAT,
Call.ATTACHMENT_ENCAPSULATION_FORMAT_DIME);

Did it work? No?! You must have done smth wrong ...

No comments: