SOA mapping layer

Introduction

XML is the ubiquitous message format in SOA. To decouple the components exchanging messages, a mapping layer can be introduced, thus isolating the knowledge on message format within this mapping layer. The obvious choice of transforming from the XML format over the wire, from the XML format within component, is XSLT.

Decoupling

The figure illustrates the basic principles of decoupling message producer from message consumer. Using a mapping layer for XSLT, and data binding, will isolate the business logic in message consumer from the xml message format. Whether a mapping layer is introduced on the message producer side, depends on design.
But the mapping layer on producer side will by the same arguments as on the consumer side introduce decoupling between business logic message format and the exchange message format.

package no.gwr.mdb.samples;

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "jms/TopicConnectionFactory"),
    @ActivationConfigProperty(propertyName = "destinationName", propertyValue = "jms/MyTopic"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
    @ActivationConfigProperty(propertyName = "SubscriptionDurability", propertyValue = "Durable"),
    @ActivationConfigProperty(propertyName = "SubscriptionName", propertyValue = "TopicListener")
})
public class OrganizationEventsListenerMDBBean implements MessageDrivenBean, MessageListener {
...

  public void onMessage(Message message) {
    try {
      if (message instanceof TextMessage) {
        TextMessage txtMsg = (TextMessage) message;
        String txt = txtMsg.getText();
        String result = transform(txt);
        Organization organization = unmarshal(result);
        MessageConsumerAdapterImpl handler = new MessageConsumerAdapterImpl();
        handler.updateOrganization(organization);
        message.acknowledge();
      }
    } catch (Throwable ex) {
      ex.printStackTrace();//TODO introduce sl4j logging framework, and log to application.log
    }
  }
	/**using XSL (xalan-2.7.1) to transform XML message*/
  public String transform(String txt) throws Exception {
    javax.xml.transform.TransformerFactory tf =  javax.xml.transform.TransformerFactory.newInstance();
    javax.xml.transform.sax.SAXTransformerFactory stf = (javax.xml.transform.sax.SAXTransformerFactory)tf;
    javax.xml.transform.stream.StreamSource xsl = new javax.xml.transform.stream.StreamSource(getClass().getResourceAsStream(XSL_FILE));
    javax.xml.transform.Templates templates = stf.newTemplates(xsl);
    javax.xml.transform.Transformer transformer = templates.newTransformer();
    javax.xml.transform.stream.StreamSource source = new javax.xml.transform.stream.StreamSource(new ByteArrayInputStream(txt.getBytes()));
    javax.xml.transform.stream.StreamResult res =  new javax.xml.transform.stream.StreamResult(new StringWriter());
    transformer.transform(source, res);
    String xmlResult = res.getWriter().toString();
    return xmlResult;
  }
  /**using JAXB (jaxb-2.2) to do the data binding*/
  @SuppressWarnings("unchecked")
  public Organization unmarshal(String result) throws JAXBException {
    Organization ret=null;
    JAXBContext jc = JAXBContext.newInstance(TNS);
    Unmarshaller u = jc.createUnmarshaller();
    JAXBElement element = (JAXBElement)u.unmarshal(new ByteArrayInputStream(result.getBytes()));
    ret=element.getValue();
    return ret;
  }
}

Summary

When doing xslt and jaxb inside a container you will most certainly run into classloading issues. But all containers have ways of controlling the application classpath to avoid some old container libraries being used from a parent classloader.

References

http://xml.apache.org/xalan-j/ for XSLT
https://jaxb.dev.java.net/ for data binding
Make sure you use JAXB 2.x,it has several improvements to 1.0. full XML schema support, generating pojos with annotations and javadoc etc.

Comment are closed.