Monthly Archives: September 2006

Web Services without Code Generation

JAX-RPC supports two major ways of developing Web services:
“bottom-up”, which allows to generate WSDL from a Java interface and “top-down”,
which generates Java classes from WSDL. Both of these approaches suffer from
one major drawback.
WSDL/Schema/mapping files or Java classes are fully re-created every time there is a need
to change Web service interface and so it becomes a developer’s responsibility to
merge existing WSDL files or Java code with the generated files. The need to manually
change WSDL/Schema stems from the fact that the generated files are usually very “basic”,
they do not take advantage of advanced schema capabilities, they
don’t use WSDL/Schema modularization and so on. Generated Java classes are even more problematic.
You really don’t want to have simple “value” classes without any behavior with fully exposed
properties. And adding behavior requires manual intervention.

In reality, there is a way to evolve two sets of artifacts (WSLD
and Java classes) independently without any generation by manually updating
Java-WSDL
mapping file
. The format of this file, however, is the antithesis of the
“convention over configuration” idea. The format is extremely verbose; each and every
field has to be mapped explicitly and so manual modification of this file poses a
real challenge for any more or less complex data structure.

The latest JEE Web service specification, JAX-WS, fixes this problem by
heavily leveraging annotations.
For data mapping, annotation support
is provided by JAXB specification. JAX-WS and JAXB finally free developers from
having to rely on the brittle code generation approach.

In fact, JAXB still supports code generation and so developers can use
it for generating Java or WSDL files. The generated artifacts could provide a good starting point for a
Web service interface. After that, however, it is pretty easy to keep both sets of
artifacts in synch by updating annotations and/or WSDL/Schema files.

How does it work in practice? Let’s say we have this very simple schema:


<element name="person">
  <complexContent>
    <sequence>
      <element name="firstName" type="xsd:string" />
      <element name="lastName" type="xsd:string"/>
    </sequence>
  </complexContent>
</element>

The following class will match the schema:


// By default JAXB uses getters/setters to drive marshaling/unmarshaling
// Using fields is easier, since they can be defined more compactly
// in one place and also moved around to manipulate order.
// Beware though - getters/setters are ignored in this case
@XmlAccessorType(XmlAccessType.FIELD)
// We need to provide the namespace, otherwise it defaults to
// the package name
@XmlRootElement(namespace="http://myarch.com/personservice")
public class Person {
    // note that JAXB marshals instance variables in the order they
    // declared
    protected String firstName;
    protected String lastName;
   ...

Note that JAXB provide several
additional attributes and annotations
which I’m not using here – I’m trying to rely as much as
I can on “convention over configuration”. Element names, for example, match my variable names,
so there is no need to provide annotations for individual fields (however, in this case,
you can’t use qualified locals
in your schema since JAXB won’t prefix nested elements.)

Many JAXB annotations, such as “XmlType” are only used for generating schema from Java classes.
Same is also true for most attributes of XmlElement.
Oftentimes developers specify “required” and “nillable” attributes of XmlElement annotation
thinking that JAXB will automatically enforce these constraints, e.g. :


@XmlElement( required = true, nillable=false)
private String lastName;

However, these parameters are not used at
run-time. JAXB 2.0 actually relies on the
schema validation framework
and so
these parameters can be omitted assuming that the schema contains the constraints.

In other words, we only have to use those annotations that help
us to correctly marshal/unmarshal our objects.

The only other step that we need to take is to create ObjectFactory class in same
package with the mapped class. In this class we need to define a factory method for the root
element of our content tree (you don’t need to worry about nested datatypes even
if they map to other classes). From what I understand, JAXB does not actually invoke any
factory methods, however, it does check for their presence in ObjectFactory.
The factory method looks simple enough:


public Person createPerson() {
    return new Person();
}

Now we can make changes to our Java classes and the corresponding WSDL/Schema files without
ever having to resort to code generation. In my mind, this is a preferred way.
We can see from Object-Relation mapping that “pure” “top-down” and
“bottom-up” don’t really exist. How often do we generate DDL from Java classes or vice versa?
Different data representations supported by different technologies have to be able to evolve
independently without having to play by each other rules. JAXB helps us to achieve it pretty easily.

Using XML Validation Framework with Web Services

A good Web service has to have a well defined and enforceable contract. Typically, the
contract is expressed using XML Schema language. Unfortunately, up until recently,
enforcing the contact was very problematic because of the huge performance overhead
associated with running schema validation. XML parsers used to load and parse the schema
for every validation request, which was clearly expensive.

This has changed with the release JAXP 1.3 which comes with the schema
validation framework
which allows to first load and compile a schema and then reuse
the compiled version for all subsequent validation requests. This may finally
make it feasible to use the schema validation for Web services in production
environment.

I decided to prototype the use of the validation framework for my Web services
implemented in XFire
(you may also want to explore a
schema validation component
implemented in ServiceMix ESB).

All it took is a fairly simple handler:


public class XFireSchemaValidationHandler extends AbstractHandler {
    
    private Schema schema = null;
    
    public XFireSchemaValidationHandler() throws SAXException{
        super();
        setPhase(Phase.PARSE);
        before(ReadHeadersHandler.class.getName());

        // Load the schema - note that handler is only
        // instantiated once, so we can keep the schema in 
        // an instance variable
        SchemaFactory factory = SchemaFactory
            .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        // I'm hardcoding the path for now, but we should be able
        // to extract it from the WSDL 
        StreamSource ss = new StreamSource(
                new File("/ws/xfire/etc/person.xsd"));
        schema = factory.newSchema(ss);
    }

	public void invoke(MessageContext ctx) throws Exception {
        InMessage message = ctx.getInMessage();
        XMLStreamReader streamReader = message.getXMLStreamReader();
        // create JDom from the stream - alternatively we can rely on
        // DOM and XFire DOM handler
        StaxBuilder builder = new StaxBuilder();
        Document doc = builder.build(streamReader);
        // get to the body first
        Element body = 
            (Element)doc.getRootElement().getChildren().get(0);
        // we assume that we use "unwrapped" mode and 
        // our payload is the direct child of the body element  
        Element payload = (Element) body.getChildren().get(0);
        
        // dump the message for testing purposes
        XMLOutputter outputter = 
            new XMLOutputter(Format.getPrettyFormat());
        outputter.output(payload, System.out);
        
        // create validation handler from the pre-complied schema
        ValidatorHandler vh = schema.newValidatorHandler();
        // the handler only works with SAX events, so we create 
        // SAX from JDom 
        SAXOutputter so = new SAXOutputter(vh);
        // Validator will run as a SAX handler and throw an exception
        // if the validation fails.
        so.output(payload);
        
        System.out.println("\nValidation passed");
        // rewind the stream reader for subsequent processing 
        message.setXMLStreamReader( new JDOMStreamReader( doc) );
	}
}

Unfortunately, the validation framework does not currently support StAX, so
an XML document has to be parsed using SAX or DOM (or JDom with subsequent SAX
conversion which is what I chose to do since it was quicker to develop
that way). I’m sure this conversion (and the validation process itself) adds
some performance overhead, but I’m hoping that it
won’t be too bad, especially for simple schemas (and from my experience 90% of
all Web services have very simple messages). JAX-RPC-compliant Web services engines
should see even less of performance penalty since everything is loaded into
DOM from the get-go. Perhaps I’ll try to run some performance tests and see what
happens.

Using XFire as a Client for WebSphere Application Server

XFire has great easy-to-use client API,
which makes it an ideal candidate for developing unit tests for Web services.
The best part is that it can interoperate with Web services implemented in other
containers and application servers. I recently started using it with IBM WebSphere Application Server (WAS) 6.1.

So what are the benefits of using XFire as opposed to a “native” Web services client
created using tools provided with your application server?

  • Many application servers/Web service containers use code generation to
    generate a client’s “proxy”. You have to remember to re-gen the client
    every time you change interface of your service.
  • Code generation has a number of issues. For example, a client generator
    will generate Java classes for parameters of a Web service. Oftentimes,
    it is desirable to use an existing class instead, so then the generated code must
    be changed.
  • Using “native” client does not test interoperability. When client and server
    are implemented using the same product, interoperability is almost guaranteed.
    Using a different client library potentially allows you to discover
    interoperability problems early on.
  • Finally, since XFire is open source, it can be packaged and distributed to
    customers and partners without requiring a license.

Invoking a Web service running in WebSphere does not require anything special:


public void testHelloService() throws Exception {
    
    Service serviceModel = new ObjectServiceFactory()
        .create(HelloService_SEI.class);
    XFireProxyFactory serviceFactory = new XFireProxyFactory();
    HelloService_SEI service = (HelloService_SEI) serviceFactory
        .create( serviceModel, 
        "http://localhost:9090/helloWS/services/HelloService");
    
    Person person = new Person();
    person.setFirstName("John");
    person.setLastName("Doe");
    String s = service.helloPerson(person); 
    assertEquals("Hello John Doe", s);
}

It must be noted though that I have not tried using any advanced features. It
would be interesting to see if, for example, XFire WS-Addressing implementation can
interoperate with WAS.

By the way, if you’re only going to use XFire client, you only a need few jars from
its distribution. Here is the list that I use (it could probably be trimmed down even more):


activation-1.1.jar
commons-codec-1.3.jar
commons-httpclient-3.0.jar
jdom-1.0.jar
jsr173_api-1.0.jar
mail-1.4.jar
saaj-api-1.3.jar
saaj-impl-1.3.jar
stax-api-1.0.1.jar
stax-utils-20040917.jar
wsdl4j-1.5.2.jar
wss4j-1.5.0.jar
wstx-asl-2.9.3.jar
xbean-2.1.0.jar
xfire-all-1.2.jar

Also, from my expreience SAAJ API only works with Sun JDK as opposed to JDKs provided by IBM as part of Rational development tools.

Choosing Between Axis2 and XFire

I used Axis 1.X in the past (not without some problems, but I was able to get the work done), and so when I needed an open source Web services stack, downloading Axis2 was my first impulse. Then, after playing with it for a short while, I had an afterthought and decided to look at XFire. I never looked back. Here are some things that made my decision not in Axis2 favor (there is actually a WS stack comparison on XFire site but I wanted to see for myself):

  • No JAX-WS or annotations support. I’m not even sure if Axis2 fully supports JAX-RPC for that matter, at least it was not obvious from the docs. I’m not a big fan of JAX-RPC (and who is?) but sometimes being able to use standard APIs is a plus.
  • Deployment model. Why invent a new “aar” archive type? So does it mean that now I have to run Ant (or the special AAR Eclipse plugin) to re-package my service every time I change a class? (It might be possible to put the exploded archive on the classpath but I did not try that.) How will this new component type integrate with app servers? How will the classloading work under different J2EE containers?
  • Data binding. It looks like there is some databinding support for the new AXIOM XML object model, but all examples use Axiom directly, so it was not very clear how to use it (at least not without resorting to WSDL2Java generator). Also, I don’t believe there is an ability to plug in different databinding frameworks such as Jaxb or Castor.

I’m sure Axis2 has a lot of good capabilities, its feature list seems impressive enough. But for now I will be sticking with XFire simply because it’s somewhat easier to setup, its API seems more intuitive, it integrates well with different conainers/app servers and also because of its JAX-WS support.

SOA Is Not the Only Form of Reuse!

Reuse is the key value proposition of an SOA. Being able to share business logic with ease by the virtue of publishing and consuming a Web service can greatly benefit an organization. But one has to realize that it is incorrect to expect SOA to meet all software reuse needs. Performance overhead of a distributed call over the network will always be a detriment to consuming a lot of fine-grained distributed functions, even with the exponential rise of network bandwidth and computing capacity. Many real-life business transactions are complex and thus require complex processing logic. Spreading this business logic over multiple service providers will undoubtedly affect performance. Consumers nowadays require instantaneous response to their requests, so businesses can’t hide the inefficiency of their architectures behind batch processes running once a day. All this means that Web services can only expose coarse-grained functions so that a number of distributed calls are kept under control. So if an application is only interested in a very discreet piece of a reusable business logic, it may not be available as part of SOA.

Reuse of UI components is another example where SOA does not have an answer. This problem can be addressed to some extent by portals. In most instances, however, it is easier to share a library of UI components among multiple applications.

In some sense, SOA was borne out of inability to achieve reuse at the library/binary level (including binary wire protocol level, such as IIOP) as it became clear that most large organizations will always run on heterogeneous infrastructures with bits and pieces supplied by multiple vendors. But I think that hype and enthusiasm created by SOA (look, our Microsoft and IBM applications can finally share some services!) somehow made everybody forget about good old library and component reuse. Granted, library reuse can only work for a given technology/platform, however, in most organizations number of these platforms is limited to very few (e.g., JEE, .NET, mainframe), so the benefits could still be substantial.

I have a feeling that SOA somehow slowed down the evolution of general purpose component management and dependency management tools as many vendors decided to focus almost exclusively on Web services. The idea of a registry/repository is very applicable to any unit of reuse, not just to a Web service. Most SOA implementation efforts put Web services registry/repository in the center of SOA, however very few organizations (as far as I know) implement general purpose component repository as a centerpiece of their development process. The repository products have been around for some time (Flashline, logidex) but their use does not seem to be very wide-spread in development organizations. Maven is becoming a de-facto standard in the Java world but its use is still pretty rare on large projects where “roll your own” is still the norm. I’m also not aware of a similar tool for .NET and other languages or of an open source or inexpensive tool that could handle component management for multiple platforms.

There is also lack of standardization. SOA suffers from overabundance of standards and specifications. Situation with component-level reuse is quite different. RAS is just too complex; MOF is geared toward modeling and MDA. SCA can be applied generically to binary components as well as to Web services, but component management is simply not in its scope.

I just hope that vendors and their customers will sooner or later realize that SOA by itself is not the goal – better business and IT efficiency (and hence better ROI) provided by software reuse is. This goal can’t be accomplished with “one size fits all” approach to software reuse.