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