Thursday, October 15, 2009

Simplifying use of JAXB Introductions

The JAXBIntros project provides a mean of using JAXB with non annotated classes, getting the required binding information from a xml config file. The information is converted into a binding customization that is basically a custom annotation reader JAXB allows as a hook for driving his context creation [1].

One of the targets of JBossWS 3.2.1 is to enable use of JAXB Introductions with the Apache CXF based stack. In order to do that I've gone through the currently available integration code between the JAXBIntro project and the JBossWS-Native stack and rationalized it to simplify the use of JAXB Introductions with every WS stack.

JAXBIntros project has been "mavenized" and the new 1.0.1.GA version is currently available in the JBoss Maven repository. It now has a convenient class (BindingCustomizationFactory) for getting binding customizations ready for being installed in a JAXB context while hiding the internals of jaxb-impl.


public class BindingCustomizationFactory {
   public static Map<String, Object> getBindingCustomization(InputStream introsConfigStream, String namespace) {
      Map<String, Object> jaxbCustomizations = new HashMap<String, Object>();
      populateBindingCustomization(introsConfigStream, namespace, jaxbCustomizations);
      return jaxbCustomizations;
   }

   public static void populateBindingCustomization(InputStream introsConfigStream, Map<String, Object> customization) {
      populateBindingCustomization(introsConfigStream, null, customization);
   }

   public static void populateBindingCustomization(InputStream introsConfigStream, String namespace, Map<String, Object> customization) {
      JaxbIntros jaxbIntros = IntroductionsConfigParser.parseConfig(introsConfigStream);
      IntroductionsAnnotationReader annotationReader = new IntroductionsAnnotationReader(jaxbIntros);
      String defaultNamespace = namespace != null ? namespace : jaxbIntros.getDefaultNamespace();

      customization.put(JAXBRIContext.ANNOTATION_READER, annotationReader);
      if (defaultNamespace != null) {
         customization.put(JAXBRIContext.DEFAULT_NAMESPACE_REMAP, defaultNamespace);
      }
   }
}


With that users can simply populate their own binding customization (which is really nothing more than a Map) and provide it when constructing the JAXBContext. That's all, the new context will consider the customizations and acts accordingly when used for marshalling/unmarshalling objects to/from xml.

Since the first release of JAXBIntros, JBossWS-Native used to have a CustomizableJAXBContextFactory getting the binding customization from the current endpoint deployment and providing it to the JAXBRIContextFactory.
Now, as previosly mentioned, enabling JAXB Introductions is just a matter of giving the customization map a way to JAXBContext creation, it doesn't matter which webservice stack is used.

As a prove of that, I've recently provided seamless integration with JBossWS-CXF. Basically CXF allows users to specify a Configurer (org.apache.cxf.configuration.Configurer) that is called whenever a configurable CXF bean is setup. JBossWS-CXF has a JBossWSCXFConfigurer (org.jboss.wsf.stack.cxf.client.configuration.JBossWSCXFConfigurer) users can leverage to configure the bus for use with JBossWS, in this case to simply plug-in binding customizations:



package org.jboss.wsf.spi.binding;
...
public class JAXBBindingCustomization extends HashMap
{

}

BindingCustomization jaxbCustomizations = new JAXBBindingCustomization();
BindingCustomizationFactory.populateBindingCustomization(getResourceURL("jaxws/cxf/jaxbintros/META-INF/jaxb-intros.xml").openStream(), jaxbCustomizations);
bus = BusFactory.getThreadDefaultBus();
originalConfigurer = bus.getExtension(Configurer.class);
JBossWSCXFConfigurer configurer = new JBossWSCXFConfigurer(originalConfigurer);
configurer.setBindingCustomization(jaxbCustomizations);
bus.setExtension(configurer, Configurer.class);
//use the bus to create the service and then invoke the endpoint



On server side the same configurer is automatically installed and it uses the binding customizations coming from the optional jaxb.intro.xml file in the deployment.

Please not that while this all comes out of the box with JBossWS-CXF 3.2.1, with "plain" Apache CXF 2.2.4 you can manually use a Configurer like the one mentioned above and/or directly provide the customization properties in the JAXBDatabinding element of the CXF Spring bus configuration file ;-)

[1] http://weblogs.java.net/blog/kohsuke/archive/2007/07/binding_3rd_par.html

Thursday, October 1, 2009

JBossWS performances: improvements coming in 3.2.1 and stacks comparison

I've recently added a few classes for running some performance tests to jbossws-framework.
Performance testing and tuning are really complex topics; generally speaking I agree with those saying that you need to establish your goals/reasons before starting dealing with optimizations, profiling, etc. My ultimate goal this time was to look for potential bottlenecks badly affecting performances, both in the JBossWS-Native stack and in the whole JBossWS framework (considering we plug CXF and Metro stacks too into JBoss AS). Needless to say, I also wanted to get a better idea of how the supported ws stack integrations compare in terms of performances... ;-)

For these reasons I basically chose a black box approach and tested the whole ws stack performing concurrent invocations to a given endpoint. Tests have been performed in two different scenarios, with the client and server hosts either living on the same LAN or on the Internet, to cope with the different latency (which you really need to consider when looking for bottlenecks / bugs in this field).

I've actually been able to work on improvements and a couple of bug fixes, which basically boosted all stacks performances, especially the Native one. Fixes are currently on trunk and already ported to the JBoss EAP branches, the next JBossWS community version including them will be the 3.2.1.GA. The 3.2.1 release is currently scheduled for the end of October.

I guess you're now looking for the numbers... Unfortunately I'm not going to write any of them here, as the results are of course influenced by the testing conditions and my goals were not to stress test all the stack in multiple conditions and come to a thorough picture of the JBossWS performances.
Anyway I do have some general considerations coming out of my tests and you can read them below. After all the tests available to the public and you are free to run them in your environment (and perhaps add more of them ;-) )
As of today (fixes will be available in 3.2.1.GA):
  • the supported stacks comes with different default logging configurations. More in details, Native is much more verbose than CXF and Metro, both client and server side. You should really want to set org.jboss.ws Log4j category (and org.jboss.wsf too) at INFO level;
  • in the medium / high latency scenario, the three stacks show comparable performances, with CXF actually giving the best results, Metro being in the middle and Native performing slightly worse than the others;
  • in the low latency scenario (LAN tests), CXF and Metro stacks run almost the same and are faster than Native stack (the gap here is bigger than in the medium/high latency scenario though).