06.30.05
Web Services, The Right Way
Lately I’ve been spending some time getting my hands dirty on document style web services. This is a job, which pulls you through the exciting disciplines of writing Web Services Description Language (WSDL) files, crafting XML Schema Definition Files (XSD), and coding a mapping between the published model and your internal service implementation. Phew.
And why on Earth, you ask, would I want to go through the hassle of getting acquainted with the details of XSD and WSDL, when there are tools which will faithfully generate a web services interface (JAX/RPC) automatically from an EJB or a Java Pojo? No need to bother, just point, click, generate, and run!
Seductive as this mechanism may seem, and indeed did seem to me for at while; it fails outright when applied in an inter-organisational SOA for a number of reasons:
- Tight Coupling. The published interface was generated directly from the underlying implementation, and hence the contract between clients and server will be fragile: Changes in the implementation’s interface ripple all the way through to clients. In a SOA we want loose couplings.
- Implementation Agnostic Contract. When a distinct model for web services is defined in the shape of an XSD file, the result is much more likely to be free of ties to the implementation of services that use it.
- Shared Model. Schema files can be imported into other schemas and reused. By defining the published model of a service in a schema, we can build upon existing entities of a shared domain.
- Versioning. The published model (XSD) can be versioned independently from the interface contract of web services (WDSL). This makes it much more flexible to implement change.
OK, great! How much work is it then? How do I even get off the ground now that I have to relate to all these XML based description languages? The good news is that it isn’t as hard as it sounds, and that nice people have made nice tools, which will aid you in this task for free.
Recipe: Axis based document style web services with a hint of XMLBeans
I originally learned this recipe from my Grandmom, who made these web services with Castor rather than XMLBeans. However, when the snow starts falling and I get into that Christmas mood, XMLBeans seem more like it with their slightly bitter, yet delicate chocolaty flavor. If short on XMLBeans, you can fall back to Castor or maybe even JAXB.
This recipe assumes that you have already downloaded and installed Apache Axis, and Apache XMLBeans.
Contracts
First define the contract (after all, this IS contract-first development). You may already have pieces of the schema at hand if you are using any public models, say GEPJ for Danish Healthcare or any of the Schemas at the OIO Database, published by The Danish Ministry of Science, Tecnology, and Innovation. Download the schemas, fire up a schema editor, and make the model. This is the bit, which takes skills slightly different from coding Java, but it isn’t that hard.
The second part of the web service interface contract is the WSDL file, which describes your service. If you don’t have a tool, I suggest you go and download Capeclear’s free SOA Editor, which will help you craft this part of the system. Otherwise, you could fall back to generating a WSDL file from the Java class as you would for JAX/RPC style web services and use this as a starting point (thank you, Tommy). Axis has a nice Java2WSDL tool, which is straightforward to use. The trick is then to separate the WSDL from the Schema part and make a reference instead. In any case, you need to import the schema(s), which happens in the types section of the WSDL as follows:
<wsdl:types>
<xsd:schema targetNamespace="http://www.silverbullet.dk/schemas/demo/1.0/MyService.xsd" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace=”http://www.silverbullet.dk/schemas/demo/1.0″ schemaLocation=”MyInput.xsd”/>
</xsd:schema>
</wsdl:types>
We will use Document Literal as the encoding style, which requires these identifiers to be in place at the right sections in the WSDL:
<wsdl:binding name="MyServiceBinding" type="tns:MyServicePortType">
<soap:binding style="document” transport=”http://schemas.xmlsoap.org/soap/http”/>
<wsdl:operation name=”MyService”>
<soap:operation/>
<wsdl:input>
<soap:body parts=”theInputMessage” use=”literal“/>
</wsdl:input>
<wsdl:output>
<soap:body parts=”theOutputMessage” use=”literal“/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
That should pretty much do the trick for the contract. Now in order to use it, we need to bring out that databinding tool.
Data Binding
Were it not for Castor, XMLBeans, JAXB, and all the others, Java developers would still be writing plain old DOM code, when accessing XML instances. In order to use these fantastic tools you typically need to invoke the dedicated schema compiler, in our case through an Ant task embedded in the Maven build script:
<goal name="xmlbeans">
<taskdef name="xmlbean" classname="org.apache.xmlbeans.impl.tool.XMLBean" classpathref="maven.dependency.classpath"/>
<mkdir dir="target/classes"/>
<mkdir dir="target/src"/>
<xmlbean destfile="target/schemas-1.0.jar" verbose="false" debug="true" classgendir="target/classes" srcgendir="target/src" classpathref="maven.dependency.classpath" schema="src/etc" includes="**/*.xsd"/>
</goal>
The XMLBeans task will generate well-named, strongly typed Java classes that can be used to create new XML instances programmatically or parse Strings, org.w3c.dom.Document instances into XMLBean trees. Nice.
The business logic
Once the published model is in place, write the business logic (if you don’t have it already). This will be the code eventually called by the web service implementation to do the actual work. You probably already have en EJB or Pojo in mind for this task, or are about to write one. Cook gently over open fire, while stirring.
A simple Web Service
Now that all the ingredients have been prepared in advance, the hallmark of the Master Chef, we are ready to start cooking with Axis. Document style web services can be implemented very simply as a Java Pojo (again, thank you Tommy), which takes an org.w3c.dom.Document as input and returns the same thing. Without exception handling, our service looks like:
public Document myService(Document document) {
MyInputDocument root = MyInputDocumentFactory.parse(document);
MyOutputDocument myOutputDocument = MyOutputDocument.Factory.newInstance();
myOutputDocument.addNewMessage().setEcho(root.getEcho() + "?! I don't know why you say goodbye, I say hello ");
XmlOptions xmlOptions = new XmlOptions();
xmlOptions.setSavePrettyPrint();
xmlOptions.setSavePrettyPrintIndent(4);
return (Document)myOutputDocument.newDomNode(xmlOptions);
}
The service contains no business logic whatsoever; it is merely concerned with mapping data from the input message to input parameters of the underlying business logic (omitted in the example), and mapping the result back to an output message. That’s it. Of course, depending on the size of the input and output schemas, this can be a slightly dull task, but hey: you stand to gain some loose coupling here!
Next we need to compile and install the web service. Axis comes with a web application, which can easily be tweaked to do what you want. Simply create a server-config.wsdd file and dump it in the $webapp/WEB-INF folder. There is one stored in axis.jar, which can be a starting point. Add in the service description:
<service name="MyService" provider="java:MSG">
<parameter name="allowedMethods" value="myService"/>
<parameter name="className" value="dk.silverbullet.ws.service.MyWebService"/>
</service>
Done, now bundle the WAR file and pack it with the EJBs in an EAR if necessary, then deploy. Et voila! Double, double toil and trouble; Fire burn and cauldron bubble (Act 4, Scene 1, MacBeth, William Shakespeare)
Testing the service
While it is possible to generate a Java client via the Axis tool Wsdl2Java, I choose to download XML Spy from Altova. These guys have a free 30 day trial edition, which will let you load a WSDL, generate an input file, and call the SOAP service. Nice and easy.
In Conclusion
So, now that the candles are lit, and that sweet, slightly burned smell of well-baked document-style services start filling the house, how do we feel? There is more work in doing web services the right way, instead of generating those prepackaged and slightly bland JAX/RPC things. But there are tools in this area too, which will assist, and the end result is sure to please the party.


