Monday, December 27, 2010

Attachments in Axis 1.4

In our "legacy" application, we have a series of classes implemented to connect to a certain 3rd party web service implementation. As this was implemented a number of years ago, it was done using axis 1.4. There are many web service calls, but the differences in their implementation is not that great, as all have core fields that are in common. Thus, the implementation we used was of the template method pattern. The use of this pattern was to encapsulate ALL the connectivity and security issues (client certificates) of using the web services in our base class. Each new web service is a trivial amount of work. All we need to do is to run wsdl2java to generate the classes, inherit our new implementation from the template base class, which then forces us to implement a number of abstract methods that include the URL of the service, as well as functions to return the request and response classes of the web service call. The template method also requests each service to add its unique data specific to that request.

So, even after our knowledgeable web services implementer moved on, this did not impede our ability to add new services, since all that plumbing was untouched code that need not be thought about. All that changed recently when we had a new web service call to add that uses attachments to send XML as an attachment. (This is third party software but I think i understand the logic of why this was done). Suddenly, the work was not as simple as it was before, and we had no axis 1.4 expert anymore and little place to turn anymore, as the world has moved forward past axis 1.4. But with such an elegant implementation it seemed worth trying to make this work within axis 1.4 and after much Googling (and even "Bing"ing), and finally some trial and error of coding, we came to an elegant solution to keep our template method pattern intact and yet still add this functionality. The main (only?) documentation i found about using attachments in axis 1.4 was here

Here is the code added to the template base class:

   1: DataHandler attachment = getAttachment();

   2: if (attachment == null) {

   3:     response = call.invoke(new Object[]{request});

   4: } else {

   5:     AttachmentPart ap= new AttachmentPart(attachment);

   6:     QName qn = new QName(namespace, "DataHandler");

   7:     call.registerTypeMapping(attachment.getClass(), //Add serializer for attachment.

   8:             qn, JAFDataHandlerSerializerFactory.class, JAFDataHandlerDeserializerFactory.class);

   9:     call.addAttachmentPart(ap);


  11:     call.addParameter("source", qn, ParameterMode.IN);

  12:     response = call.invoke(new Object[]{request,attachment});

  13: }

The first line calls a new method getAttachment which is not abstract (or final). This means that we can add this functionality without having to implement it in all the implementing classes. The default implementation of the base class returns null and the new class we have will obviously override this and return the attachment of type javax.activation.DataHandler.

If we have an attachment, the steps we need to take are:
  • On Line 5 we wrap this attachment in an Axis class AttachmentPart
  • On Line 7-8, we need to register this attachments using the serializer/serializer JAFDataHandler that will handle the serializing and deserializing of the attachment. Note that the name “DataHandler” is just what i made up.
  • Line 9 adds the attachment to the call
  • Line 11 adds the attachment as a parameter to the call
  • Line 12 includes our request class and the attachment in the actual call.
One other change we needed to make was that since until now we always had only one parameter, we did not need to register the first parameter, but now this became necessary in order to add the second.

And in these few lines since our use of the template method pattern enabled us to keep our complex implementation intact and still accomodate this new functionality.

1 comment: