A meta-guide to technical web service design

In this blog entry I present a simple technique to create technical web service designs using a Java based tool chain.

Some background

At first I wanted to title this entry: A meta-guide to technical web service design for geeks or how not to shoot yourself in the foot. Looking back at past experiences, that is exactly what happens; for some inexplicable reason service interface design is neglected and we end up with a great number of web services that accept input similar to the following:

1
2
3
4
5
  <request xmlns="http://www.openuri.org/">
       <input>
          <![CDATA[<hello>world</hello>]]>
      </input>
  </request>

Passing XML (as a string) within an XML wrapper is not very self describing. The XSD used to describe the XML instance document above will not contain the required hello structure (line 3), it will only describe the input element (line 2) as being of type xsd:string. This leaves the poor consumer of the web service completely in the dark with no idea what the actual required input to the service must be (by just looking at the WSDL document). Bam!, you just shot yourself in the foot, fielding 10 calls a day from people asking what the input to the service should be. And how about that XML namespace (line 1); I won’t even bother talking about the (mis)use of XML namespaces, not to mention the problems caused by not qualifying XML documents properly.

Web Services technologies are possibly the most pervasive in realising or exposing the functional aspects of SOA services today. Put another way: service developers encounter web services and the related standards (XSD, WSDL, SOAP, etc) on a daily basis. By placing web services in an SOA context it becomes very clear that the above example doesn’t do very much to deliver on the promise of SOA services. The importance of designing web services with clean and self describing interfaces (at a technical level) cannot be underestimated and is an absolute must within an SOA context.

The meta-guide

How do we do technical web service design to ensure clean and self describing interfaces? Let’s first establish some basic requirements that must be satisfied by the web service design process:

  1. All service interfaces must be strongly typed and document oriented. This implies that our design efforts will always result in Document style web services. Document style web services align well with message oriented integration initiatives.
  2. The design must be interface driven i.e the functional contract of the service must be defined in an abstract manner (no implementation).
  3. The output of the design process must produce the following artifacts:
    1. Documentation to communicate the service design.
    2. XSD artifacts that represent the data model of the required service inputs and outputs.
    3. WSDL artifacts that represent the functional contract of the service.

From a personal perspective I would like to add a few more requirements:

  • The design process should encourage a healthy dose of DRY[1] (Don’t Repeat Yourself) . For the purpose of this discussion it implies that it must be possible to take the deliverables from the design process and realise a service implementation*.
  • I don’t like authoring WSDL documents by hand and haven’t found any tooling that simplifies this task to be any less error prone than it actually is doing it by hand. The only (and safest) option left is code generation (see the Rule of Generation[2]). The design process must therefor facilitate the use of Java interfaces to define the functional contract of the service and provide tooling to generate the WSDL document**.

Below is a description of the tool chain that will be used to drive the design process and address the requirements.

  • Apache XMLBeans[3]. XMLBeans is a technology for accessing XML by binding it to Java types. XMLBeans address requirements 1 and 3(b) by providing full support for XML Schema Definitions (XSD). Full XML Schema support is important because it allows service designs to take full advantage of the power of XML Schema and not have to restrict themselves to a subset of supported features. This does however imply authoring XSD documents as part of the design process.
  • JAX-WS[4]. The Java API for XML Web Services (JAX-WS) defines a Web Services API to develop Web Services solutions. Put differently to address the specific requirements (2, 3(c)) of the design process; JAX-WS facilitates the definition of web services using Java interfaces by providing a Java <-> WSDL mapping and a set of annotations to express this mapping.
  • Apache CXF[5]. Apache CXF is an open source services framework that implements the JAX-WS specification. The framework provides tools and infrastructure to help build and develop services. In addition to providing a TCK compliant JAX-WS implementation, the framework also supports alternate data bindings including XMLBeans.
  • Apache Ant[6]. Apache Ant is used to drive the build process responsible for code, documentation and WSDL generation.
  • Javadoc[7]. The Javadoc tool is used to generate online documentation from the XMLBeans and service interface(s) and addresses requirement 3(a).
  • UMLGraph[8] doclet. UMLGraph is an optional requirement. UMLGraph provides an alternate Javadoc doclet implementation that is capable of generating UML diagrams for inclusion in online Javadoc documentation.

Now we know about the tools. The image below outlines the design process to produce a technical service design using the tool chain described above.

Let’s step through the process using a very simple example.

We are required to design a service capable of generating simple greetings given a name and surname. The service should also raise a fault when a greeting cannot be created. Using the design process described above we do the following:

  1. Create XSD’s: We start by defining the required data model for all of the service inputs and outputs.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:sim="java:simple.service.data"
                targetNamespace="java:simple.service.data"
                elementFormDefault="qualified">
     
      <xsd:complexType name="InputData">
        <xsd:sequence>
          <xsd:element name="Name" maxOccurs="1"
                       minOccurs="1" type="xsd:string"/>
          <xsd:element name="Surname" maxOccurs="1"
                       minOccurs="1" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
     
      <xsd:element name="InputData" type="sim:InputData"/>
     
      <xsd:complexType name="OutputData">
        <xsd:sequence>
          <xsd:element name="Greeting" maxOccurs="1"
                       minOccurs="1" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
     
      <xsd:element name="OutputData" type="sim:OutputData"/>
     
      <xsd:complexType name="SimpleServiceFault">
        <xsd:sequence>
          <xsd:element name="message" maxOccurs="1" type="xsd:string"/>
        </xsd:sequence>
      </xsd:complexType>
     
      <xsd:element name="SimpleServiceFault" type="sim:SimpleServiceFault"/>
    </xsd:schema>

    XSD Guidelines:

    • Qualify your service data model with an appropriate XML namespace (line 3 and 4).
    • First define xsd:complexType definitions as illustrated in lines 7 – 14. Then define elements based on the xsd:complexType definitions. (line 16).
    • Define xsd:complexType definitions and the associated elements for all the faults that could be generated by the service (if any). This is illustrated in lines 27 through 33.

    It is important to familiarise yourself with XSD. The w3schools website contains a good XML Schema Tutorial[9].

  2. Generate the XMLBeans API and Data Model Documentation. This generates a Java API, based on the XML Schema input, that is capable of marshalling and unmarshalling XML document instances that adhere to the XML Schema Definition. This task can be automated with Apache Ant by employing the XMLBeans provided XMLBean[10] task and the Apache Ant Javadoc task[11].

  3. Create Service interface(s) in Java and annotate with JAX-WS. We can now define the functional contract of our web service using a simple Java interface. You will notice that the method parameters and return types are interfaces from the generated XMLBeans API.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    
    /*
     * $Id$
     *
     * Description:
     *
     */
     
    package simple.service;
     
    import javax.jws.*;
    import javax.xml.ws.*;
    import simple.service.data.*;
     
    /**
     * A simple business service interface. Provide a fairly detailed high level
     * description of the functional capabilities of the service.  Perhaps provide
     * hyperlinks to the documented business requirements addressed by the service.
     *
     * <p>The following list provides access to the WSDL design artifacts for this
     *    service:
     * <ul> 
     *  <li><a href="../../../wsdl/simple/simpleService.wsdl">WSDL (Source)</a>
     * </li>
     * </ul>
     * </p>
     *
     * @author Hannes Holtzhausen
     */
     
    @WebService(name = "SimpleService",
                serviceName = "SimpleService",
                targetNamespace = "java:simple.service")
    public interface SimpleService
    {
      /**
       * Operation to create a simple greeting.
       *
       * @param  input  The InputData instance that must be used to create a 
       *                greeting.
       *
       * @return  output  The OutputData instance that contains the greeting. 
       */
     
      @WebMethod (action = "sayHello")
      @WebResult (name = "OutputData",
                  targetNamespace = "java:simple.service")
      public OutputData sayHello(
                  @WebParam (name = "InputData",
                             targetNamespace = "java:simple.service")
                  InputData input) throws SimpleServiceException;
     
      /**
       * Operation to create another simple greeting.
       *
       * @param  input  The InputData instance that must be used to create a 
       *                greeting.
       *
       * @return  output  The OutputData instance that contains the greeting. 
       */
     
      @WebMethod (action = "sayGoodbye")
      @WebResult (name = "OutputData",
                  targetNamespace = "java:simple.service")
      public OutputData sayGoodbye(
                  @WebParam (name = "InputData",
                             targetNamespace = "java:simple.service")
                  InputData input) throws SimpleServiceException;
    }

    Interface Guidelines:

    • Qualify your interface with an appropriate package name. (line 8).
    • Provide a clear and detailed description of the service in the class level javadoc comment (lines 14 – 28). These comments will be incorporated into the generated documentation.
    • Qualify your service with an appropriate XML namespace and name using JAX-WS annotations. (lines 30 – 32). You will notice that the service namespace (java:simple.service) is different from the data model namespace (java:simple.service.data). This is done on purpose to provide a separation between the data model and the service model.
    • Qualify your methods (i.e parameters and return types) with appropriate XML namespaces using the JAX-WS annotations (lines 44 – 50).
    • Exploit as much of the JAX-WS functionality (through annotations) as possible to ensure an accurate mapping between the interface and the resulting WSDL document.
    • You will notice that our interface throws a service specific exception (line 50). Review sections 2.8 and 3.7 of the latest JAX-WS Specification[4] for guidelines on defining service specific exceptions.

    Familiarise yourself with JAX-WS. A good place to start is the JAX-WS Users Guide[12] provided with the reference implementation.

  4. Compile Service interface(s) and Generate the Service Documentation. This can be achieved with Apache Ant by using the Apache Ant Javac and Javadoc tasks[11].

  5. Generate WSDL document(s) using the Apache CXF java2ws tool. Apache CXF provides the java2ws[13] tool that is able to generate WSDL artifacts from a set of annotated interfaces/classes. You can use the Apache Ant Java task[11] to launch the tool and generate the WSDL artifacts.

You can browse the generated documentation*** of the example we just discussed here[14].

Notes

  1. * Most technical designs I have come across are authored using a certain popular word processing tool. More often than not the functional requirements (operations and data structures) are presented in table like structures. Before a technical person can even begin an implementation he/she must first create a set of interface artifacts like XSD’s and WSDL’s for web services or Java Beans and Java Interfaces for Java applications. I am of the belief that the technical design process should provide all (or most) of the required interface artifacts to enable developers to get on with the job at hand.
  2. ** I don’t want to get into any arguments here around contract first or code first development. From my (geek) perspective a Java interface defines a functional contract, is abstract and does not contain concrete implementation details. With this in mind, the design process documented here addresses the requirement around defining the functional contract in an abstract manner. As an aside, the primary concern of most people that promote contract or WSDL first development is around full XML Schema support when using a code first approach. I agree with this sentiment, hence my decision to opt for XMLBeans as XML binding technology i.e full XML Schema support using a code first approach [for functional service definitions].
  3. *** Some browsers might display a blank page while browsing the XSD and WSDL artifacts of the example content. View the source code of the page or frame to see the artifact content. (I have an XSLT stylesheet to convert XML to HTML but I was to lazy to integrate it into the build, maybe later.)

Links

Happy Hacking!

This entry was posted in programming, SOA, Web Services and tagged , , . Bookmark the permalink.