Thursday, December 20, 2007

Scanning the Class Path with Spring 2.5

I was writing a test to check the consistency of a collection of classes. The desired behavior was to scan the class path starting from a base package, to filter the classes using some criteria and to check the resulting classes for the presence of a combination of annotations. I needed a piece of code that takes care of the scanning bit. It’s not rocket science but this kind of code could be recurrently useful.
I happened to remember that the newly released Spring 2.5 integrates a similar behavior. I peeked into the code and found that ClassPathScanningCandidateComponentProvider was responsible for that part. The key method is findCandidateComponents, which returns a set of bean definitions.

Here's a method based on ClassPathScanningCandidateComponentProvider that loads and returns the classes it finds:

public Set<Class<?>> scanClassPath(String basePackage,
 TypeFilter includeFilter, TypeFilter excludeFilter)
 throws Exception {
 Set<Class<?>> result = new HashSet<Class<?>>();
 ResourcePatternResolver resourcePatternResolver = 
  new PathMatchingResourcePatternResolver();
 String packageSearchPath = 
  ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
 if (basePackage != null) {
  packageSearchPath += ClassUtils
   .convertClassNameToResourcePath(basePackage);
 }
 packageSearchPath += "/**/*.class";

 MetadataReaderFactory metadataReaderFactory = 
  new CachingMetadataReaderFactory(
   resourcePatternResolver);

 Resource[] resources = resourcePatternResolver
   .getResources(packageSearchPath);

 for (Resource resource : resources) {
  MetadataReader metadataReader = metadataReaderFactory
    .getMetadataReader(resource);
  ClassMetadata classMetadata = 
   metadataReader.getClassMetadata();

  if (includeFilter != null
    && !includeFilter.match(metadataReader,
      metadataReaderFactory)) {
   continue;
  }

  if (excludeFilter != null
    && excludeFilter.match(metadataReader,
      metadataReaderFactory)) {
   continue;
  }
  Class<?> class1 = Class.
   forName(classMetadata.getClassName());
  result.add(class1);
 }
 return result;
}
Advantages:
  • Class files are treated as plain files, no loading occurs before a class is needed.
  • MetadataReaders provide useful information about the scanned classes without loading them, including the name of the class, whether it is concrete or abstract, the name of its super class and the implemented interfaces and even information about its annotations.
  • TypeFilters can be used to include or exclude classes. Spring 2.5 provides a couple of implementations.
It is also possible to subclass ClassPathScanningCandidateComponentProvider in order to reuse its behavior. Here’s an example with an anonymous class that loads the classes returned by findCandidateComponents:

result = new ClassPathScanningCandidateComponentProvider(false){
 {
  addIncludeFilter(
   new AssignableTypeFilter(A.class));
  addExcludeFilter(
   new AssignableTypeFilter(B.class));
 }
 Set<Class<?>> scan(String basePackage) {
  Set<Class<?>> classes = new HashSet<Class<?>>();
  Set<BeanDefinition> beanDefinitions = 
   findCandidateComponents(basePackage);
  for (BeanDefinition def : beanDefinitions) {
   try {
    classes.add(
     Class.forName(def.getBeanClassName()));
   } catch (ClassNotFoundException e) {}
  }
  return classes;
 }
}.scan("my.base.package");

Monday, November 26, 2007

My (fairy) Story with Spring

Once upon a Time

TSS has recently published an updated version of the article "Introduction to the Spring Framework" by Rod Johnson. It reminded me of my beginnings with Spring.

It was late 2003 when I stumbled across the first version of that article. My first reaction was "yet another framework". The introduction intrigued me however, so I decided to give it a try. The article struck a chord. I was working on a couple of "typical" J2EE projects back then: a Struts web layer and an EJB2 service layer, plus an always-growing amount of custom infrastructure code. We also used a collection of J2EE patterns throughout the different layers. EJB2 was a mess, Struts was expiring and most of the patterns were of dubious benefit. Everyone knows that now. Back then, that was the standard.

Prince Charming


The article was so enlightening. Spring presented a compelling alternative based on simple and sound principles. Its integration and configuration capabilities immediately interested me. Now new technologies could be integrated smoothly while keeping the configuration externalized and centralized. The numerous and homogeneous abstraction layers finished off convincing me to adopt Spring for my next project.

It took some more reading and research to decide on switching to Spring MVC, although I was aware of Struts shortcomings. Moving to a slightly better framework was not enough. However, the smart and pragmatic design in addition to the uniform configuration model tipped the balance in favor of Spring MVC.

So here came the next project. It was a web application. We implemented a simple layered architecture making use of several Spring components right from the start, mainly Spring MVC for the web layer, Hibernate and JDBC templates/callbacks, declarative transaction management and even some Spring AOP. The whole application was managed and wired by the Spring container. The improvement was quite spectacular.

And They Lived Happily ever after


I moved on to other stuff and enjoyed using various technologies of the Spring portfolio throughout my work. My first Spring application continued to live and to evolve until the time came when it was decided to give it a complete revamp by a different team. The new version was planned to run in a Portlet environment as well.

Two things struck me as remarkable after the new version took shape. First, a large portion of the business code was reused. Second, even the web layer, which I usually consider as disposable, was recuperated and transformed to Spring MVC Portlet with reasonable efforts.

I took a moment to muse about my experience with Spring. Retrospectively, I think that beyond the direct benefits, Spring simply enabled me to write good code. Good code is reusable.Good code is uncluttered and free of unnecessary dependencies.

I have a pet peeve though, regarding Spring’s perception by newcomers. By taking care of the tedious details, Spring could obscure how things work on a lower level. It might even be hard for some people to grasp the point of using Spring when they haven’t been confronted with the problems it solves in the first place. It's normal that what's good eludes you when you haven't been through the bad!

Wednesday, July 11, 2007

Using Groovy ConfigSlurper to Configure Spring Beans

The latest preview release of Groovy (1.1-beta-2) introduced ConfigSlurper, a new class that enables usage of scripts similar to Java property files, for configuration. ConfigSlurper scripts support native Java types and are structured like a tree. Being Groovy scripts, they also support the regular Groovy features. To put things shortly, ConfigSlurper scripts can be seen as property files on steroids!
Spring offers a couple of configurer objects that allows for configuration of bean properties with Java property files. My goal is to implement a configurer that uses ConfigSlurper scripts instead. As an example (from the Spring reference documentation), using PropertyPlaceholderConfigurer:

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>
Here's the associated property file:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql:production:9002
jdbc.username=sa
jdbc.password=root
With ConfigSlurper we could write something like this:
def normalize(s){
   return s.toUpperCase()
} 

jdbc{
    driverClassName=org.hsqldb.jdbcDriver
    url=jdbc:hsqldb:hsql:production:9002
    username=normalize('sa')
    password=normalize('root')
}
Notice that in addition to the usage of scoping to avoid repetition, we can employ basically any Groovy construct inside the script. Needless to say, this example aims to show some of the possibilities, not to represent a relevant use case.

Integration with Spring

The integration is surprisingly simple thanks to the flexibility of both Spring and Groovy. ConfigSlurper parses a script and produces a ConfigObject. A ConfigObject can be merged with another ConfigObject (coming from another script) and finally transformed to a java.util.Properties.

As a base for our GroovyPlaceholderConfigurer, I'm using PropertyPlaceholderConfigurer. Thus, the usual behaviour of property parsing and resolution can be preserved. We only need to redefine the loadProperties method in order to plug the ConfigSlurper in. Here's the code:

public class GroovyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
  private Resource[] locations;

  @Override
  protected void loadProperties(Properties props) throws IOException {
    ConfigObject configObject = new ConfigObject();
    ConfigSlurper configSlurper = new ConfigSlurper();
    for (Resource l : locations) {
      configObject.merge(configSlurper.parse(l.getURL()));
    }
    props.putAll(configObject.toProperties());
  }

  public void setLocations(Resource[] locations) {
    this.locations = locations;
  }

  public void setLocation(Resource location) {
    this.locations = new Resource[] { location };
  }

}
To use it, we need to define a bean in the application context:

<bean class="cafebabe.GroovyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:config.groovy</value>
            <value>classpath:config2.groovy</value>
        </list>
    </property>
</bean>
That's it!

Monday, May 14, 2007

Flexible Endpoints for Spring-WS with Groovy

Typically, endpoints have the responsibility of extracting information from incoming XML, invoking a service from the service layer and transforming the result to XML back again. They don't usually contain "interesting" business logic but they are the first server-side elements to be impacted by changes in the web service's interface. They also might have to deal with different XML messages from different clients. Although not very sophisticated, writing and maintaining endpoints tend to be repetitive and time-consuming . Groovy can bring some flexibility and agility to that.

So, What does Groovy Offer?

Groovy has a couple of neat features that can add value to endpoint development:

  • GPath: GPath is an expression language integrated in Groovy and used to access parts of structured data easily . GPath allows to navigate through XML using the dot notation. So a.b.c means <c> inside <b> inside <a>. To access an attribute, @ is used: a.@x means attribute x of element <a>. Writing an expression for a nonexistent path is possible and does not throw an exception. This flexibility allows for simple duck typing. Of course GPath has other possibilities. We will use GPath to extract information from the request.
  • Builders: special Groovy syntax used to construct arbitrary tree structures. Calling any method on a builder produces an element with same name. The value as well as attributes are specified as parameters of the call. We will use DOMBuilder and NamespaceBuilder to produce the XML of the response.
  • Spring integration: Groovy has an excellent integration with Spring. Spring 2 "refreshable beans" feature allows to refresh a bean definition written with Groovy without reloading the whole context. Thus, it is possible to update endpoints while our application is online.

Groovy Endpoints

Our Groovy endpoints will extend a base abstract class: AbstractGroovyEndpoint. AbstractGroovyEndpoint will transform the request's payload into a GPathResult which is the Groovy object that supports GPath navigation. Concrete endpoints will implement the abstract Source invokeInternal(GPathResult request) in order to access the request.
Before going into the integration details, lets take an example and see how our Groovy endpoints will look like.

An Example

The following XML represents our request. It will be used to query a service about a list of items. Each item is represented by an <item> element. Its reference can be found either in a ref attribute or a nested ref element:

<c:queryItemsRequest xmlns:c="http://cafebabe">
    <item ref="cat"/>
    <item ref="dog"/>
    <item ref="bird"/>
    <item>
        <ref>dog</ref>
    </item>
</c:queryItemsRequest>
The response looks like the following:

<c:queryItemResponse xmlns:c="http://cafebabe">
    <item ref="cat">A cat!</item>
    <item ref="dog">A dog!</item>
    <item ref="bird">No description found for bird</item>
    <item ref="dog">A dog!</item>
</c:queryItemResponse>
The endpoint extracts the references of the items to query using GPath. It looks for each reference first in a nested <ref> element and then in a ref attribute. After that the service is invoked. Finally, the response is built using Groovy builders and a javax.xml.transform.Result is returned as specified by Spring-WS:

class QueryItemEndpoint extends AbstractGroovyEndpoint {

  QueryService queryService

  protected Source invokeInternal(GPathResult request){
    def items = []
    for(item in request.item){
      Item i = new Item()
      i.ref = item.@ref == "" ? item.ref : item.@ref
      items.add(i)
    }
 
    items = queryService.query(items)
  
    def builder = DOMBuilder.newInstance()
    def xsd = NamespaceBuilder.newInstance(builder, 'http://cafebabe', 'c')
    def response = xsd.queryItemResponse(){
      for (i in items){
        item(ref: i.ref, i.desc)
      }
    }
    return new DOMSource(response)
  }
Finally, the bean definition in Spring:

<lang:groovy
    id="queryItemEndpoint"
    script-source="/groovy/QueryItemEndpoint.groovy"
    refresh-check-delay="1000">
  <lang:property
      name="queryService"
      ref="queryService" />
</lang:groovy>
Notice the refresh-check-delay attribute that tells Spring that this is a refreshable bean. Spring will check whether the delay has expired and refresh the Groovy script if necessary.

Integration with Spring-WS

Spring WS relies on Source/Result interfaces from the javax.xml.transform to abstract XML handling. Groovy defines an XmlSlurper class that parses XML using SAX and produces a corresponding GPathResult object. XmlSlurper is a stateful object that implements org.xml.sax.ContentHandler. The trick is to create a javax.xml.transform.sax.SAXResult with an instance of XmlSlurper as a content handler and to transform the Source of the request using it:

public abstract class AbstractGroovyEndpoint extends TransformerObjectSupport
    implements PayloadEndpoint {

  public final Source invoke(Source request) throws Exception {
    XmlSlurper slurper = new XmlSlurper();
    Transformer transformer = createTransformer();
    SAXResult result = new SAXResult(slurper);
    transformer.transform(request, result);
    GPathResult document = slurper.getDocument();
    return invokeInternal(document);
  }

  protected abstract Source invokeInternal(GPathResult request);

}

Remarks

Groovy endpoints I have shown are probably best suitable for services that need to be flexible in the way they deal with clients' requests. GPath is intuitive and easy to write and modify. On the other hand, it is not as powerful as XPath. Also all the collection mapping and data type conversions have to be taken care of "by hand".
The source code can be downloaded here.

Thursday, April 19, 2007

Customizing Display Tag Rows with JQuery

Display Tag is quite flexible, yet it lacks some customization possibilities. I had the requirement of customizing the rows of a table generated by display tag.
I had to attribute a specific CSS class to each row of my table depending on the value of a specified column. I found one solution on the net with javascript. I'm not a big fan of javascript (the language, not its usage). I always find myself struggling with the syntax, the DOM tree and the cross-browser issues.

Enter JQuery!

JQuery has caught my eye recently. I was impressed by its simple structure and powerful selectors. For me, it made sense.
Let's take the following display tag table as an example:
<dt:table name="list" id="displaytag" >
    <dt:column property="date" title="Date" sortable="true"/>
    <dt:column property="type" title="Type" sortable="true"/>
    <dt:column property="value" title="value"/>
 </dt:table>
Here's how to attribute a CSS class depending on the value of the second column with JQuery:
$(function() {
$("#displaytag tr[td:nth-child(2):contains('value1')]")
  .attr("class", "style1");
});
In plain English this reads: select from the table with the id "displaytag" all rows whose second column contains "value1", and set their class attribute to "style1". JQuery selectors use a mix of CSS and XPath in addition to other elements. Their power enables this kind of one liners although they might seem confusing at first.
Here's another example hardly more complicated: how to modify the value of the third column depending on the value of the second:
$(function() {
$("#displaytag tr[td:nth-child(2):contains('x')]>td:nth-child(3)")
  .append("xxx");
});
That's it!

Thursday, March 15, 2007

Migrating Smoothly from rpc/encoded to document/literal Web Services with Spring-WS

I've recently had to migrate Axis 1.x based web services to Spring WS. The Axis web services were rpc/encoded whereas the new ones use document/literal style. Rpc/encoded style is not portable, generates bulky XML which is difficult to validate. However, I think they are still common for different reasons. In this context, migrating clients to the new service implies rewriting parts of their code. This could be difficult to manage if the service is public and the clients are heterogeneous, specially if they are not under your direct control. I thought about a simple way to achieve a smoother migration with Spring WS that I would like to share in this post.

The Idea

The basic idea is to detect the incoming rpc/encoded requests and to transform them to the new structure on the fly using XSLT. The responses to the transformed requests have to be transformed back again the XML expected by the client. This way the clients can use the new web service only by pointing to its endpoint. Because of the added overhead by XSLT, this solution is probably not long-term. It is more suitable in a transitory period to allow each client to adapt its code according to its own schedule and constraints.
Spring WS has a transforming interceptor that can take care of the transformation part. I will extend it so that:

  • It recognizes and transforms rpc/encoded requests. Document/literal requests will not be altered.
  • It marks the transformed requests in order to transform back their responses.

An Example

I will use a familiar example: an online store. The OrderRequest class represents a client's order and contains a DeliveryInfo object containing an address and a delivery date, and a list of items to order. An Item has a reference and a quantity. The server responds with the reference of the order.

For the sake of brevity, I'll show only the interesting parts. Here's and example of the rpc/encoded payload of an order with 2 items:

<caf:placeOrder soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <o xsi:type="caf:OrderRequest">
        <info xsi:type="test:DeliveryInfo">
            <address xsi:type="xsd:string">abc</address>
            <deliveryDate xsi:type="xsd:date">2007-04-01</deliveryDate>
        </info>
        <items xsi:type="test:ArrayOfItem" soapenc:arrayType="test:Item[1]">
            <item>
                <quantity xsi:type="xsd:int">10</quantity>
                <ref xsi:type="xsd:string">123</ref>
            </item>
            <item>
                <quantity xsi:type="xsd:int">5</quantity>
                <ref xsi:type="xsd:string">345</ref>
            </item>
        </items>
    </o>
</caf:placeOrder>
And the response payload:
<ns1:placeOrderResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://cafebabe">
    <placeOrderReturn href="#id0"/>
</ns1:placeOrderResponse>
<multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:long" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">123456</multiRef>
Here's the target document/literal request payload:
<caf:orderRequest>
    <info>
        <address>abc</address>
        <deliveryDate>2007-04-01</deliveryDate>  
    </info>
    <items>
        <item>
            <quantity>10</quantity>
            <ref>123</ref>
        </item>
        <item>
            <quantity>5</quantity>
            <ref>345</ref>
        </item>
    </items>
</caf:orderRequest>
And the corresponding response:
<ns3:orderResponse xmlns:ns3="http://cafebabe">
    <orderId>123456</orderId>
</ns3:orderResponse> 
We need two XSLT stylesheets, one to transform the requests (rpc->document) and the other for the responses (document->rpc). First request.xsl:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:caf="http://cafebabe">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="no"/>
    <xsl:template match="/caf:placeOrder/o">
        <caf:orderRequest>
            <info>
                <address><xsl:value-of select="info/address"/></address>
                <deliveryDate><xsl:value-of select="info/deliveryDate"/></deliveryDate>
            </info>
            <items>
            <xsl:for-each select="items/item">
                <item>
                    <quantity><xsl:value-of select="quantity"/></quantity>
                    <ref><xsl:value-of select="ref"/></ref>
                </item>
            </xsl:for-each>
            </items>
        </caf:orderRequest>
    </xsl:template>
</xsl:stylesheet>
And response.xsl:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:caf="http://cafebabe" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    <xsl:template match="/caf:orderResponse">
        <caf:placeOrderResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <placeOrderReturn href="#id0"/>
        </caf:placeOrderResponse>
        <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:long" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
            <xsl:value-of select="orderId"/>
        </multiRef>
    </xsl:template>
</xsl:stylesheet>
Basically, each stylesheet copies the target XML structure and extracts the values using XPath expressions.

The Transforming Interceptor

As I mentioned earlier, the transforming interceptor is based on PayloadTransformingInterceptor from Spring WS. Its basic outline is as follows:
public class RpcTransformingInterceptor extends PayloadTransformingInterceptor {
    private static final String SOAP_ENCODING = "http://schemas.xmlsoap.org/soap/encoding/";
...
  public boolean handleRequest(MessageContext messageContext, Object endpoint)
      throws Exception {
    WebServiceMessage message = messageContext.getRequest();

    if (isRpc(message)) {
      setRequestTransformed();
      return super.handleRequest(messageContext, endpoint);
    }
    return true;
  }

  public boolean handleResponse(MessageContext messageContext, Object endpoint)
        throws Exception {
    if (isRequestTransformed())
      return super.handleResponse(messageContext, endpoint);
    return true;
    }
...
}
First we need to mark each transformed request. Spring 2 supports request scope which is just what we need. I will define a simple inner class BooleanHolder in my RpcTransformingInterceptor and add a request-scoped property transformed:
public class RpcTransformingInterceptor extends PayloadTransformingInterceptor {
  public static class BooleanHolder {

    private boolean value = false;

    public boolean getValue() {
      return value;
    }

    public void setValue(boolean value) {
      this.value = value;
    }
  }

  private BooleanHolder transformed;

  private void setRequestTransformed(){
    transformed.setValue(true);
  }

  private boolean isRequestTransformed(){
    return transformed.getValue();
  }
We have to write a bean definition in the Spring context:
<bean id="transformed" scope="request" class="cafebabe.ws.RpcTransformingInterceptor$BooleanHolder">
    <aop:scoped-proxy />
</bean>
For earlier versions of Spring, it is possible to use a ThreadLocalTargetSource instead.

Now, we have to read the encoding style of the payload. If it is equal to http://schemas.xmlsoap.org/soap/encoding/ the request will be transformed. Working with Sun's implementation of SAAJ 1.3 I found out that calling getSaajMessage().getSOAPBody().getEncodingStyle() returns null. We will have to read the encodingStyle directly from the payload. Spring WS gives access to the payload via WebServiceMessage.getPayloadSource(). Because we are only reading a small part of the message, StaX seems appropriate for the job:

...
private static XMLInputFactory inputFactory = XMLInputFactory.newInstance();
...
private boolean isRpc(WebServiceMessage message)
            throws XMLStreamException {
  XMLStreamReader parser = inputFactory.createXMLStreamReader(message.getPayloadSource());
  parser.nextTag();
  String encodingStyle = parser.getAttributeValue(
      "http://schemas.xmlsoap.org/soap/envelope/"
      , "encodingStyle");
  return SOAP_ENCODING.equals(encodingStyle);
}
I also implemented a DOM version:
...
private static TransformerFactory transformerFactory = 
    TransformerFactory.newInstance();
...
private boolean isRpc(WebServiceMessage message)
        throws TransformerException {
  Transformer transformer = transformerFactory.newTransformer();
  DOMResult domResult = new DOMResult();
  transformer.transform(message.getPayloadSource(), domResult);
  Element rootElement = (Element) domResult.getNode().getFirstChild();
  String encodingStyle = rootElement.getAttributeNS(
        "http://schemas.xmlsoap.org/soap/envelope/"
        , "encodingStyle");
  return SOAP_ENCODING.equals(encodingStyle);
}
That's it! Now the interceptor will transform the rpc/encoded message in a transparent way for the client and the server. Make sure that you place it first in the chain of interceptors, at least before the validation interceptor if you use one.

Performance and other Considerations

I used JAXB 2 for Java-XML binding with Spring WS and soapUI for all the tests. I also used the default message factory (SaajSoapMessageFactory).
There are several StaX parsers. Only Woodstox worked for me. For example, SJSXP and StaX-RI threw exceptions when calling createXMLStreamReader (message.getPayloadSource()). Actually, Woodstox threw an exception when I tried to use AxiomSoapMessageFactory but worked fine with SAAJ.

Obviously the transformation overhead depends on the complexity of the XML. However, I wanted to measure the overhead added by the interceptor to examine each request, even non transformed ones. I wanted also to compare between the DOM version and StaX version. I conducted the tests with two kinds of messages: a small message containing 2 items and a bigger message containing 400 items (size around 47k). I set soapUI to launch 5 concurrent threads for 5 minutes with a test delay of 1 second. I repeated the tests 5 times and calculated the average. Please note that the results are relative as there is no business logic executed by the service (100% of the time is spent in the framework and XML processing). Here are the results:
Small payloadOverheadBig payloadOverhead
No interceptor~435 tpsN/A~35 tpsN/A
DOM (no transformation)~400 tps8%~23 tps34%
StaX (no transformation)~415 tps5%~34 tps3%
StaX (with transformation)~377 tps13%~20 tps43%
Knowing that SAAJ messages are DOM documents I was surprised by the bad results of the DOM version. Transforming a DomSource to a DomResult seems to duplicate the whole document (I checked with a debugger and found different object ids) so it is a costly operation. However, StaX doesn't add a significant overhead and its performance doesn't degrade with larger messages.

The Bottomline

  • The interceptor doesn't add significant overhead to examine incoming messages. Compliant requests will not suffer a loss of performance.
  • Performace tests should be conducted per case to determine if the overhead of the XSL transformation is acceptable or not.
The source code can be downloaded here.

Monday, March 5, 2007

Securing Spring-WS Client with XWSS

Warning: this post is now obsolete. Spring-WS WS-Security now work on the client side as well.

I was really excited about the new release of Spring Web Services (M3) and its new client side API. I like the simplicity and the elegance of the template based approach which is already used in various parts of Spring. In this post, I will show you how I used XWSS to add WS-Security support to web services invocations.
I used XWSS 2.0 from jwsdp-2.0. I had to add xmlsec.jar from the jwsdp-shared/lib in order for the example to work.