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 ...

Tuesday, March 11, 2008

works as designed

You definitely heard this one, developers use it as a reason for closing bugs, you even used it yourself. It sounds perfectly natural, at least to me, the developer. I bet testers hate it. 3 simple words to close a bug with.

And now I'm questioning if the construct is correct. How much sense does design make to a tester? And considering that some teams have this open policy where clients can see all the product bugs, how much sense does design make to a client?

To find out the answer, try this: in UAT, go to your client and tell her that the bug she thinks she found is actually the behavior as designed. Don't be surprised if she asks you What design? Now if you are smart you'd shut up and go check the spec that she counter-signed, if you are not-so-smart (read stupid or inexperienced) you'd say: What design?! The UML class design, the interaction and ORM diagrams!
By now the smart reader noticed that the works as designed construct is flawed. If this is the case, then my proof worked as specified.

P.S. If I were the client, I'd only sign contracts that say the software vendor must ship works as intended software.