Monday, April 8, 2013

Soap Model Duplication / Mitigation


Soap Model Duplication / Mitigation
When creating a soap interface (or any other external api) after you already have a very big internal model base can be very difficult.
The optimal architectural design is to have two model bases one internal and one external. The reason for this is to decouple internal code from external. Usually the external interface does not change much and refactoring is not an option (since the clients are already using this interface). On the other hand internal structures are always being refactored to meet new requirements. If the subset functionality needed to be exported is well defined, then the decision is usually strait forward, since the external api by requirement will be different from the internal.
The problem is that if your model is very big and the requirement are to export all internal functionally then we have the problem of duplicating the full model (which can be tens if not hundreds of classes).
In any case when having a dto we need a simple way to covert from the external api to the internal and vice versa.
When looking from above there are two major options (in the case of xml based protocols). In the case of soap the protocol is based on xml documents. So any request is converted from xml to an object and then the result is converted from the object back to xml.
So if we need to transform the request from the external api to the internal api, we can either do it on the object level or on the xml level.
The object level is the more known way to do conversions since it is not protocol specific, and can be done on the external level in code. The disadvantage is that the transformations are not always easy and need an external framework to help (see http://dozer.sourceforge.net/). Another disadvantage is that the code becomes very “dirty” with a lot of lines just for the transformation.
Another option that I want to expand on is the option for transformation on the xml level. Since the protocol of soap is based on xml and xsd schemes, there is an option of transforming the incoming and outgoing xml using xslt. Xslt is widely known and has a lot of transformation capabilities (http://www.w3schools.com/XSL/).
In this solution you have only one model base and do the transformations on the xml level and not on the object level.
Using a framework like CXF (http://cxf.apache.org/) for soap, it is very easy to add xslt files for your soap requests.
The way CXF works, is that for every incoming and outgoing request there is a list of interceptors that are called. The message is sent to each interceptor (order can be set) in the chain before and after. So the soap request will pass through the interceptors, and one of them will do the transformations.
CXF supports two types of transformations: StaxTransformFeature, XSLTFeature.
The difference between the two, I copied from the site of CXF (http://cxf.apache.org/docs/xslt-feature.html):

When should I use Transformation Feature and when XSLT Feature?

If only trivial transformations must be done, it is recommended to use lightweight and fast Transformation Feature. It covers the most use cases as:

·          dropping the namespace of the outbound messages;

·          qualifying the incoming message;

·          changing namespaces;

·          appending or dropping elements;

·          converting attributes to elements.

Transformation Feature is completely stream oriented and work fast especially for large messages.

If you should apply non-trivial transformation, not supported by Transformation Feature - it is use case for XSLT Feature. Here you can write any custom XSL Transformation and apply it to inbound and/or outbound messages.
As far as Xalan XSLT engine is actually not completely stream oriented, XSLT Feature breaks streaming. However it uses high-performance DTM (Document Table Model) instead complete DOM model.
Performance can be improved in the future by using further versions of Xalan or other XSLT engines (like Saxon or STX oriented Joost).


I will describe how to use the XSLTFeature since we need a full xsl file to transform the requests.

In the application context of the CXF where you define your endpoints you need to define the following:
<bean id="xsltFeatureSoapTestService" class="org.apache.cxf.feature.transform.XSLTFeature">
       <property name="inXSLTPath" value="soapTransformers/requestTransformation.xsl" />
       <property name="outXSLTPath" value="soapTransformers/responseTransformation.xsl" />
</bean>
<jaxws:endpoint implementor="#soapTestService" address="/ws/SoapTestService">
       <jaxws:features>
              <ref bean="xsltFeatureSoapTestService" />
       </jaxws:features>
</jaxws:endpoint>

The first bean is what the interceptor will use. You need to create one per endpoint, since this bean will hold the in and out xls. Then on your endpoint you add the jaxws:features with a reference to your bean.
This will cause the CXF to run the transformers on the incoming message and the outgoing message.
To start testing this you can use a simple xsl that actually just copies the original xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:sapiens="http://soap.interfaces.internal.foundation.alis.sapiens.com/">
       <!-- Identity Template # Copy everything -->
       <xsl:template match="@*|node()">
              <xsl:copy>
                     <xsl:apply-templates select="@*|node()" />
              </xsl:copy>
       </xsl:template>
</xsl:stylesheet>

Then to easily remove a specific property from the xml you can write:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:sapiens="http://soap.interfaces.internal.foundation.alis.sapiens.com/">
       <!-- Identity Template # Copy everything -->
       <xsl:template match="@*|node()">
              <xsl:copy>
                     <xsl:apply-templates select="@*|node()" />
              </xsl:copy>
       </xsl:template>
      
       <!-- remove text -->
       <xsl:template match="msgText">
       </xsl:template>

</xsl:stylesheet>

This will remove the xml element of msgText from the xml.

As you can see it is very easy to remove attributes or nodes from the soap xml model, or to do any transformation that you need on the xml level, and not on the object level.

No comments:

Post a Comment