Keep up with the Web service styles (and uses)

Control SOAP formats to avoid interoperability issues

It's a perfectly reasonable goal for a Web service toolkit and runtime engine: allow a developer to take a server interface, brand it a Web service, and automatically generate some client-side proxy code from it, all without ever having to eyeball an XML document.

That would be fine if all Web service platforms generated SOAP messages the same way. But, as Web service developers are finding out these days, they don't. And the formats some use by default to produce the XML in SOAP messages are losing ground as the preferred formats in the field. Worse, if two different Web service platforms provide differing levels of support for a certain formatting scheme, watch out when you need to run a client on one and a service on another.

The first part of this article explains the two central decisions developers make when forming SOAP messages—style and use—and how they relate to:

  • The communication patterns that Web services support
  • Existing Java specifications
  • The high-level mechanisms for translating between Java methods and SOAP messages
  • The fundamental Web service design choices

The second part shows how to control style and use—starting from both server-side Java and an XML Web service definition—using two Web service platforms:

  • Apache Axis 1.1, an open source Web service toolkit and runtime engine.
  • Systinet WASP Server 4.5.1 for Java, a commercial Web service toolkit and runtime engine. (Version 4.6 was recently released.)

Part 1: Untangling the terminology

Nowadays, Web service developers are being bombarded with catchphrases: "document/literal," "RPC-style," "message-style," and so on. And judging from mailing list threads and even seminar presentations, not only are many developers just confused about the terms' precise meanings, they are also confusing the terms with each other.

Actually, such misunderstanding is perfectly understandable, considering the imperfect evolution of Web service practices, as you'll see.

SOAP and WSDL XML

First, let's establish some basic, baseline knowledge of the XML in both a SOAP message and a WSDL (Web Services Description Language) document, which defines a Web service. (Speaking of imperfect evolution, the acronym "SOAP" has sloughed off its original meaning, Simple Object Access Protocol.)

A typical SOAP message viewed down to the second level follows:

<soap:Envelope
                                       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" >
                                       <soap:Header>
                                       <!-- header element(s) here -->
                                       </soap:Header>
                                       <soap:Body>
                                       <!-- body element(s) here -->
                                       </soap:Body>
                                       </soap:Envelope>
                                    

The <soap:Header> element is not required for the core SOAP functionality discussed in this article and can be omitted. Essentially, the canvas we're trying to paint is the contents—the children, grandchildren, and so on—of the <soap:Body> element.

Here is an abridged version of a typical WSDL document viewed, for the most part, down to the second level:

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl"
                                       targetNamespace="your namespace here"
                                       xmlns:tns="your namespace here"
                                       xmlns:soapbind="http://schemas.xmlsoap.org/wsdl/soap">
                                       <wsdl:types>
                                       <xs:schema targetNamespace="your namespace here (could be another) "
                                       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                                       <!-- Define types and possibly elements here -->
                                       </schema>
                                       </wsdl:types>
                                       <wsdl:message name="some operation input">
                                       <!-- part(s) here -->
                                       </wsdl:message>
                                       <wsdl:message name="some operation output">
                                       <!-- part(s) here -->
                                       </wsdl:message>
                                       <wsdl:portType name="your type name">
                                       <!-- define operations here in terms of their messages -->
                                       </wsdl:portType>
                                       <wsdl:binding name="your binding name" type="tns:port type name above">
                                       <!-- define style and transport in general and use per operation -->
                                       </wsdl:binding>
                                       <wsdl:service>
                                       <!-- define a port using the above binding and a URL -->
                                       </wsdl:service>
                                       </wsdl:definitions>
                                    

The standard namespaces in a WSDL document are as follows:

  • http://schemas.xmlsoap.org/wsdl: Abbreviated wsdl or made the default namespace
  • http://schemas.xmlsoap.org/wsdl/soap: Abbreviated soapbind, wsdlsoap, or soap. The elements in this namespace provide the SOAP binding, specifying that the WSDL refers to SOAP messages and not messages of some other type. The soapbind namespace is used for elements within the <wsdl:binding> and <wsdl:service> elements.
  • http://www.w3.org/2001/XMLSchema: Abbreviated xsd, for XML Schema definitions, which use the XML-based definition language laid out in the W3C XML Schema specification. Used within the <wsdl:types> element.

A quick explanation of the six featured elements follows:

  • <definitions>: The root node.
  • <types>: Contains one or more <xsd:schema> elements. Within each <schema> element are simple and complex XML datatype definitions using XML Schema, and, optionally, XML element declarations.
  • <message>: Defines an XML message placed inside a SOAP message's body. For every request-response operation, you have one uniquely named request message and one uniquely named response message (plus possibly fault messages indicating errors), so don't be surprised if you have to scroll through a thicket of <message> elements for a Web service with numerous operations. Each message is defined in terms of the types under <types>.
  • <portType>: Defines an abstract Web service interface in terms of its operations, where each operation is defined in terms of the above messages.
  • <binding>: Defines a concrete Web service implementation (except for the URL) in terms of the above port type, the use of SOAP, as well as the two XML formatting decisions: style for the entire service (or less commonly, per operation), use per operation.
  • <service>: Defines a port, or Web service destination, in terms of the above binding plus a URL. The <service> element is intended to locate a Web service, but obviously you have to know where the Web service is to get to the WSDL in the first place. Alternative location mechanisms, like UDDI (Universal Description, Discovery, and Integration), go beyond the scope of this article.

Gnarly though it may appear, the WSDL format has a certain elegant logic. Note how each lower element type depends on and builds upon the one just above it: A service's port commits a binding to a URL. A binding commits a port type to certain XML formatting rules. A port type's operations are made up of messages. Messages are made up of types, or elements.

The figure below shows the relationships between the salient elements of a WSDL document.

A high-level representation of WSDL element relationships based on a sample WSDL document. Click on thumbnail to view full-size image.

The described WSDL involves a Web service port-binding-portType with a single operation, GetSomething, which uses two messages, GetSomethingRequest and GetSomethingResponse. The figure is color-coded according to namespace. Upward-pointing arrows indicate dependencies where a bold-faced name is derived.

Armed with this knowledge, we can now address some of the touchy issues involved in SOAP message formation.

Patterns, styles, and uses

With Web services, you can think of three communication patterns:

  • RPC (remote procedure call): Client sends a server a SOAP request and waits for a SOAP response.
  • One-way messaging: Client sends a SOAP request and expects no SOAP response back.
  • Asynchronous callback: Client calls service; later, the two parties switch roles for a callback call. This pattern can be built from either of the first two.

Asynchronous callbacks are a topic worthy of their own discussion, but for now, just understand that the pattern exists. As for RPC and one-way messaging, the difference between the two is really quite trivial: one produces a SOAP response and the other doesn't.

In the WSDL, that difference amounts to whether the <wsdl:operation> element contains a <wsdl:output> element in addition to <wsdl:input>. The operation should be defined in both <wsdl:portType> and <wsdl:binding>.

Now we turn to the two decisions for formatting the contents of a message's <soap:Body> element.

The style, or binding style, decision controls how the elements just under the SOAP body are constructed. The two choices are:

  • RPC: Add extra elements to simulate a method call. (Note that RPC is also a communication pattern.)
  • Document: Just send the XML as is. There's also a variation called wrapped that is still specified as document.

Here's an example of an RPC-style message:

<tns:matchNoteAndNote xmlns:tns="urn:outline.demo">
                                       <in0 xsi:type="xsd:string">0000000000</in0>
                                       <in1 xsi:type="xsd:string">000000000B</in1>
                                       </tns:matchNoteAndNote>
                                    

RPC relies on some rules. Observe that the root element is qualified with a namespace, but the two child elements use unqualified names. The root element is named after the operation: opName for a SOAP request, opNameResponse for a SOAP response. Each child is a parameter, or a return value named opNameReturn.

Now here's an example of a document-style message:

<out:getNoteResponse xmlns:out="urn:outline.demo">
                                       <out:note key="000000000B" >
                                       <out:content>test</out:content>
                                       </out:note>
                                       </out:getNoteResponse>
                                    

Observe that all elements are defined within the same namespace. With a document-style Web service, you're free to define the XML however you wish because all the XML is explicitly specified.

Next, we examine how binding style is specified in the WSDL. There actually is a style attribute in the <soapbind:binding> element, which is the <wsdl:binding> element's first child. Also, each nonempty <wsdl:message> has one or more <wsdl:part> child elements, into which style factors.

Table 1 illustrates the differences between RPC and document:

Table 1. How binding style is specified in a WSDL document

 RPCDocument
<soapbind:binding> elementstyle="rpc"style="document"
<wsdl:part> element(s)Any number of <part> elements, each containing a type attributeSingle <part> element containing an element attribute; zero also allowed

The essence of the distinction lies in the above use of a type attribute versus an element attribute. With document style, you're placing into the SOAP body an XML element that is fully specified under the <wsdl:types> element. With RPC style, you're just specifying the type so the SOAP engine, using RPC rules, can make it a parameter, or a return value, and then place that parameter and any siblings inside an operation.

The second decision, use, or encoding, concerns how types are represented in XML. The two choices are:

  • Literal: Literally follow an XML Schema definition
  • SOAP encoded: Follow special encoding rules detailed in the SOAP 1.1 specification (Section 5, to be precise) to produce XML that can contain references pointing within the message

Here's an example of a SOAP-encoded message (with an RPC style):

<ns1:getNoteResponse
                                       soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                       xmlns:ns1="urn:outline.demo">
                                       <getNoteReturn href="#id0"/>
                                       </ns1:getNoteResponse>
                                       <multiRef id="id0" soapenc:root="0"
                                       soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
                                       xsi:type="ns2:Note"
                                       xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
                                       xmlns:ns2="urn:outline.demo">
                                       <key xsi:type="xsd:string">000000000B</key>
                                       <content xsi:type="xsd:string">test</name>
                                       </multiRef>
                                    

Notice how there's a reference, href="#id0", pointing outward to a complex type instance, <multiRef id="id0">. This XML expresses the same Note instance shown much more succinctly in the earlier document-style example, which happens to employ literal usage. In fact, with SOAP encoding, the roundabout references are optional when an instance is pointed to only once. A Web service runtime could take the time to check for a single reference and produce more literal output instead. In fact, it should according to the SOAP 1.1 spec.

What's difficult to notice in this message is that, for all the attributes and namespace declarations, none of the actual data fields are represented as XML attributes. SOAP encoding automatically maps all eligible fields to elements, not attributes. With the literal use of an XML schema, on the other hand, you can specify what items are attributes and what items are elements. In the above getNoteResponse example, the simple key field can be written more compactly, and arguably more legibly, as an attribute.

Now we can examine how use is specified in the WSDL. A use attribute is found via the following XPaths:

  • /definitions/binding/operation/input/soapbind:body[@use]
  • /definitions/binding/operation/output/soapbind:body[@use]
  • /definitions/binding/operation/fault/soabind:fault[@use]

Faults are ignored herein for simplicity. Table 2 explains the differences between SOAP encoded and literal:

Table 2. How use/encoding is specified in a WSDL document

 SOAP encodedLiteral
<soapbind:body> use attributeuse="encoded"use="literal"
Other <soapbind:body> attributesencodingStyle="http://schemas.xmlsoap.org/soap/encoding/"Optional: parts attribute referring to a <wsdl:part> name

Understanding the misunderstandings

It's time to finally address the misconceptions surrounding the three SOAP XML formatting decisions—three if you count the communication pattern along with style and use. In fact, the worst misconception might be the inability to see the three separate decisions. Many developers mistakenly suppose only a single choice can be made from the choices shown in Table 3:

Table 3. Mistaken either-or #1

 PatternStyleUse
EitherRPCRPCEncoded
OrOne-way messagingDocumentLiteral

Theoretically, you should be able to mix and match any of the patterns, styles, and uses. Practically, the style/use combinations have limitations. Many Web service platforms don't directly support RPC/literal. And document/encoded? Sort of like combining sweatpants with a dress shirt. So you're typically left with document/literal and RPC/encoded.

But throw communication patterns into the ring and the gloves are off. Nothing prohibits you from using a document/literal Web service for RPC communications; in other words, you don't need to use RPC style for RPC. Likewise, choosing document/literal doesn't mean you're developing a message-style service. (For now, ignore the term "message-style," which has taken on another meaning, explained shortly.) Point is, don't confuse the data with how it's being used. One source of this confusion is that SOAP's roots lie in RPC/encoded for RPC communications.

Now document/literal is gaining momentum for all communication patterns. The Web Services Interoperability Organization (WS-I), an industry consortium whose members include IBM, Microsoft, and BEA, in August finalized a Basic Profile Version 1.0a specification that details which Web service specs to use and how to use them. The Basic Profile 1.0 rules out the use of SOAP encoding, leaving document/literal and RPC/literal as the only allowed style/use combinations. The WS-I has generated some controversy, but the fact is, it's an indication of where Web services are headed.

Let's now bring transport protocol into the equation. HTTP is the one transport protocol that SOAP 1.1 must support; others are optional. But here comes another misconception: take the earlier mistaken either-or and add another column:

Table 4. Mistaken either-or #2

 TransportPatternStyleUse
EitherHTTPRPCRPCEncoded
OrSMTP or other mail protocolOne-way messagingDocumentLiteral

Okay, so you can't do RPC over mail protocols because there's no response. But you can do one-way messaging over HTTP. To put it another way, one-way messaging does not imply a message-based transport protocol. (Actually, one-way notification would be a better name.)

Consider that the definition of one-way is transport-neutral: the WSDL operation has no <wsdl:output>, that is, no SOAP response. Whether the SOAP client waits for an HTTP response is an implementation detail, although blocking obviously locks the client into HTTP.

There's a parallel confusion between one-way messaging/notification and asynchronous callbacks. Many developers assume they're one and the same. But situations arise where you might want to notify a service without needing a reply later. Think logging. By the same token, a pair of one-way messages doesn't necessarily suffice for an asynchronous exchange. The initial call might need a synchronous acknowledgment, and the callback call (where the client and service switch roles) might need an ack as well.

JAX specs

Unfortunately, the relevant Java specifications can compound some of the confusion. The three specs are:

  • Java APIs for XML-based RPC (JAX-RPC): Defines the mappings between the SOAP world of Web service endpoints, WSDL, and XML datatypes and the Java world of service and client classes and Java types. My previous JavaWorld article, "Axis-orizing Objects for SOAP," (April 2003) explains how JAX-RPC translates between XML datatypes, and Java classes and primitives.
  • Java API for XML Messaging (JAXM): A lightweight API that focuses on the communication patterns involved with the transmission of SOAP messages, rather than the contents of those messages.
  • Java Architecture for XML Binding (JAXB) 1.0: Specifies a "compiler" to convert XML Schema definitions into Java classes, plus extra XML-based binding declarations files. A runtime engine translates back and forth between objects and XML.

First contrast JAX-RPC and JAXM. Chances are you'll find JAX-RPC more useful because most likely, you'll want to translate between XML datatypes and Java types in addition to accessing the raw XML via a javax.xml.soap.SOAPMessage object, which you can do anyway with either spec.

The problem with JAX-RPC is it has extremely limited support for document/literal. Basically, it only does literal use when the use doesn't veer far from SOAP encoding. When a JAX-RPC-compliant runtime engine encounters a message part that doesn't have a standard Java mapping, it bails and produces an unbound SOAPMessage object. And what's non-standard? Attributes, for one thing, because JAX-RPC doesn't use extra metadata to decide whether a Java property should be an element or attribute.

But couldn't JAX-RPC use JAXB and its XML-based binding declarations to do that? It could, but it doesn't. Other Web service platforms do keep track of this metadata one way or another. WASP's WSDL2Java tool accomplishes this by generating a proprietary .xmap file with a root <mapping> element. Underneath that element is the schema, and within each type definition is a <map> element specifying the corresponding generated Java class. At runtime, the WASP server picks up this file, if present.

Thankfully, the specs are moving targets, as you can see from the 1.x versions. There's a JAX-RPC 1.1 spec under review that will support document/literal bindings and the WS-I Basic Profile. A preview implementation is available with the new Java Web Services Developer Pack 1.2.

Ideally, JAX-RPC would use JAXB as a foundation. Plus, there wouldn't be two separate JAX-RPC and JAXM specs. Why integrate JAX-RPC and JAXM? It comes down to a simple, stupid—duh!—revelation: regardless of whether you're using SOAP to emulate a method call or to just blindly send XML documents, ultimately the <soap:Body>'s content is still an XML document (XML with a single root element).

Styles that aren't styles

Actually, there's nothing stopping you from placing multiple children in the <soap:Body>, leaving you with arbitrary XML that doesn't constitute an XML document. For this, there is what Apache Axis calls the message style of Web services. (Never mind that any SOAP communication involves a message.) More generally, a message-style Web service, a la Axis, parses or passes along arbitrary XML, without automatically binding it to non-XML-related Java types.

Rather than stop with the SOAPMessage object as JAXM does, though, Axis gives access to the objects found in methods that follow certain required signature forms. (See the documentation.) The Axis-specific deploy.wsdd deployment descriptor file must also specify a message-style service.

Apache Axis 1.1, released June 16, identifies four styles of service:

  • Document
  • RPC
  • Message
  • Wrapped

Document and RPC correspond to the same-named binding styles from the WSDL schema. Axis considers both message style and wrapped as document/literal. (Granted, message style can violate document style by offering more than one parent element.)

Stop a moment and gather the implication of that last paragraph. Message and wrapped are not truly binding styles. WSDL is oblivious to them. Rather, they are code-level mechanisms for binding between SOAP messages and methods. So you could say that, within document style, there are three code-level binding styles: document, message, and wrapped.

Wrapped does something akin to RPC. That is, it "wraps" the method parameters in a parent element representing the operation. The difference is it does so before the XML definition gets to the class definition, thus encapsulating the wrapping from the Java methods.

The Axis 1.1 documentation provides a good example for comparing a document-style code-level binding with a wrapped-style code-level binding. Suppose when you take a purchase order, the three inputs are item, quantity, and description: A code-level document binding would give you: public void method(PurchaseOrder po). A code-level wrapped binding would give you: public void purchaseOrder(String item, int quantity, String description). Either way, the WSDL comes out the same. Wrapped-style is more restrictive in that there always has to be that extra parent element enclosing 0-n parameters, but it does spare the developer the busywork of writing code to take a document method parameter and open it up to get to the real parameters. And an orthodox document-style binding at the code level needs to specify a single document element anyway, regardless of the number of parameters.

Data-centric Web service development

Go back to our obvious revelation: in the normal case, the SOAP body always contains an XML document. From that, you can make a decent argument that the best way to design an industrial-strength Web service is to work with the XML from the ground up. Start by defining a WSDL and XML Schema types, and then use that XML to autogenerate a server source.

For me, at first glance, the idea of XML-oriented Web service development sounded like reverse engineering. After all, it's easy enough to take an existing object-oriented application, add a Web service-ready façade in the form of a Java interface, and let the Web service tools and runtime worry about generating the SOAP.

Yet, the XML (in the form of SOAP messages) is what the client interacts with. Therefore, according to the start-with-the-XML line of thinking, it is the SOAP messages and not the Java code that should take priority for optimization, and should be composed, not generated. As you will see in the next section, taking this approach typically means writing extra code to reconcile an XML-oriented Java interface with the interface of the existing server application that you're probably trying to make into a Web service to begin with.

The rest of this article will show how to control style and use from both starting points, Java server code and WSDL/XSD. Of course, in the latter case, you control style and use via the WSDL itself; aside from code-level style decisions, the remaining deployment work amounts to realizing a WSDL without regard to its style/use. This article only touches on WSDL composition.

Part 2: Control style and use

Our how-to starts with Apache Axis and moves to Systinet WASP (Web Applications and Services Platform). Merely for demonstration's sake, procedures will try to produce document/literal Web services.

Axis patch-and-match

First a warning. Our Axis walkthrough will travel down several different avenues towards a document/literal Web service. All will prove dead ends because, while Axis purports to support document/literal, it actually doesn't. So really, this section is merely an academic exercise. The lessons, though, extend beyond Axis.

Start with the direct route. Suppose you're using Axis tools and the Axis Web application, and you have a Java interface representing a Web service endpoint. Your deployment steps will run roughly as follows:

  1. Compile server code.
  2. Run Axis's Java2WSDL tool on the compiled interface and other server code to generate a WSDL document.
  3. Run Java2WSDL's counterpart, WSDL2Java, to generate a deploy.wsdd deployment descriptor.
  4. With the application server or servlet container running, execute Axis's AdminClient to deploy deploy.wsdd to the Axis Web application. Also copy server code to the Axis Web application.

You might also want to run WSDL2Java to generate client proxy source, which would then be compiled with composed client consumer code. WSDL2Java generates client proxy source automatically.

Well, the preceding step-by-step is not fully possible with Axis if you wish to control style and use. While Java2WSDL provides style and use command-line options, specifying them produces error messages. From the command line, Java2WSDL only recognizes its default, RPC/encoded. The equivalent Ant task, Axis-java2wsdl, provides a style attribute whose values are three of Axis's service styles: RPC, DOCUMENT, WRAPPED. But the document/literal DOCUMENT and WRAPPED choices fail; only RPC works.

So let's try our first detour. Instead of having Axis generate the WSDL, make the WSDL document and any XSDs it imports Axis's first input. That doesn't mean you have to handcraft the WSDL yourself; you can still generate the WSDL using some other Java-to-WSDL—or whatever-language-to-WSDL—tool.

In fact, since interoperability is the essence of Web services, it should be possible to mix and match Web service toolkits along the discrete deployment stages:

  1. Use one toolkit to generate the WSDL.
  2. Use another toolkit and runtime engine to generate server code from the WSDL and then run the Web service.
  3. Use yet another toolkit and runtime engine to generate client proxy code from the WSDL and then run a test client.

WASP, as you will see, can take a shortcut along this path, but you get the idea. As long as we're trying WASP, let's substitute WASP's Java2WSDL in the Axis process.

Below is a sample command-line invocation of WASP's Java2WSDL. (WASP tools can also be invoked via Ant and from within certain IDEs.) Examples follow a sample "Outline" Web service, whose primary source lies in a demo.outline package and whose Java service interface is named demo.outline.Outline:

Java2WSDL.bat
                                       --output-directory projectRoot\output\waspAutoSource
                                       --force 
                                       --classpath classpathHere 
                                       --output-file-mapping urn:outline.demo=outline.wsdl
                                       --package-mapping demo.outline=urn:outline.demo 
                                       --class-mapping demo.outline.Outline=http://localhost:8080/axis/services/Outline
                                       --service-mapping demo.outline.Outline=Outline
                                       demo.outline.Outline
                                    

The --service-mapping argument maps the Web service endpoint class to a specified name for a <wsdl:service>. Java2WSDL also offers --soap-binding-style and --soap-encoding-style options, whose default values are document and literal, respectively. Hence their absence.

Following is the start-from-the-WSDL deployment sequence for Axis, which applies regardless of whether the WSDL has been generated or composed:

  1. Execute WSDL2Java on the WSDL to produce deploy.wsdd plus server code
  2. Write code to tie together generated and already-existing server source
  3. Compile all the server code to the Axis Web application
  4. With the server running, execute AdminClient to deploy deploy.wsdd to the Axis Web application

For Step 1, feed Axis's WSDL2Java the outline.wsdl file that WASP generated. Below is that command-line invocation (Ant task available also):

java org.apache.axis.wsdl.WSDL2Java
                                       --output projectRoot\output\axisAutoSource
                                       --deployScope Application
                                       --server-side
                                       projectRoot\output\waspAutoSource\outline.wsdl
                                    

The --server-side option says to generate service deployment descriptors, including deploy.wsdd, and service source.

The Axis WSDL2Java's default code-level behavior for document-style binding is to wrap if possible. There is an option, --noWrapped, to turn off wrapping and use an orthodox document binding, but it's not yet implemented.

Suppose hypothetically that Axis's Java2WSDL tool supported document/literal. Then if you started from Java and had wrapping on for both Java2WSDL and WSDL2Java, you could tell Axis to make the implementation class it uses at runtime be your original implementation of the service endpoint Java interface. (In deploy.wsdd, you would replace the value of the className attribute in the containing <parameter> element.) But if you start from the WSDL, you have no such certainty. Instead, you must rely on WSDL2Java to generate a template implementation class with a name of the form BindingName_BindingImpl or BindingNameSoapBindingImpl. All the methods are there but empty—that is, nothing between the { }.

Filling in these implementations is the point where you accomplish Step 2: "Write code to tie together generated and already-existing server source." In our example, each method in Outline_BindingImpl just calls the equivalent method in the actual OutlineImpl class. Alternatively, if you have already verified that your own implementation class has the same interface as BindingName_BindingImpl, you can just sub in the former for the latter.

So how does this pairing of WASP's Java2WSDL with Axis's WSDL2Java fare? Well, Axis does generate Java, but there are some issues.

First, there's the merely annoying. The WASP-manufactured WSDL is full of WASP-specific artifacts—artifacts you wouldn't notice if you were using WASP straight-through. For one thing, WASP produces various type definitions in its own namespace. For instance, the dedicated parent element of a String[] mapping translates to a Java class in a WASP namespace, com.systinet.wsdl.java.lang.ArrayOfstring. Worse, WASP proliferates fault types, one for each endpoint method that throws a custom exception, even when the methods throw the same custom exception type. Axis has no choice but to produce one exception class for each fault type. You can edit these artifacts out of the WASP WSDL.

Then there's where the annoying meets the doesn't-work. WASP defines within its own namespace, http://systinet.com/xsd/SchemaTypes/, global elements for complex types that are defined in the developer's namespace, for example urn:outline.demo. Rude but valid. At runtime, Axis places the complex type content in the SchemaTypes namespace, via a default namespace. An example follows:

<Note_Response xmlns="http://systinet.com/xsd/SchemaTypes/">
                                       <key>0000000000</key>
                                       <name>Test</name>
                                       <parent xsi:nil="true"/>
                                       <content>Test content.</content>
                                       </Note_Response></pre>
                                    

This is wrong. The child elements inherit the SchemaTypes namespace when they should use the urn:outline.demo namespace. Any self-respecting SOAP client would ignore these children. Again, your workaround is to edit the WASP WSDL: make all its element declarations use your own namespace.

By this point, you could be doing so much WSDL editing, you might think this is as tedious as writing a WSDL from scratch. But by the same token, you can see that relying on the verbatim output of a Web service platform's Java-to-WSDL tool—or its runtime WSDL generation if an intermediary WSDL isn't needed—can be troublesome the moment you have to look under the hood. With a do-it-yourself WSDL (edited or from scratch), you can avoid proprietary definitions, however benign, and moreover have a handle on what's going on. Of course, the trade-off is you have to go to the trouble of having a handle on what's going on.

Okay, before resorting to writing a WSDL, let's try one small hack to trick Axis to do document/literal. Run Axis's Java2WSDL assuming the default RPC/encoded, then WSDL2Java. Next, edit deploy.wsdd. In the <service> element just under the root <deployment> element, change the style and use attributes' values from rpc and encoded, respectively, to document and literal. Also, set the <typeMapping> elements' encodingStyle attributes to "".

Alas, with this change, invoking the Axis Web application to dynamically obtain a WSDL document, via a ?wsdl URL parameter, produces the same kind of error that Java2WSDL produces for document/literal.

And so, finally we reach our last resort, composing a WSDL oneself, which actually isn't such a bad resort, if you know what you're doing. In lieu of a step-by-step, here are a few tips. The obvious one is to start with a generated WSDL, even an RPC/encoded WSDL generated by Axis.

Because we're doing document style, every input or output message body should consist of at most one message part corresponding to an element declaration. This is where document-style WSDL writing gets tricky. Even though the code-level binding choice between document and wrapped doesn't apply to the WSDL itself, you can't help but consider that decision and the method signatures that will result. Really, wrapped is preferable to "orthodox document," for reasons that can be broken down by the number of parameters in a method:

  • Two or more parameters: If the parameters map to elements, you need to wrap them in a single parent element anyway. You might as well encapsulate that wrapper element—and its corresponding complex type, not to mention that type's corresponding Java class—from your binding implementation class.
  • Zero parameters: If you don't use a wrapper element, an empty SOAP body will be sent, like so: <soap:Body />. So how can the Web service know which operation is being called? You could specify in the WSDL the presence of a SOAPAction HTTP header, but this commits you to HTTP. And anyway, Axis has difficulty recognizing the SOAPAction header. The same logic applies for a void return type.
  • One parameter: You already have what you can make the contents of a single element. But you might as well wrap that element inside another anyway. Otherwise, you're being inconsistent, putting the real data one layer down in some cases and in the top layer in others.

Now it's time for the true tedium. For every method, create an input wrapper element with the same name as the method, plus an output wrapper element with Return appended to the method name. The corresponding complex types should have, for child elements, any method parameters or the return value.

Suppose you want Axis to do a wrapped binding for a method signature with no parameters or returns:

public void checkIntegrity();
                                    

Then the <wsdl:types> section should contain the following (where tns is the target namespace):

<xsd:element name="checkIntegrity" type="tns:CheckIntegrity" />
                                       <xsd:element name="checkIntegrityReturn" type="tns:CheckIntegrityReturn" />
                                       ...
                                       <xsd:complexType name="CheckIntegrity">
                                       <xsd:sequence></xsd:sequence>
                                       </xsd:complexType>
                                       <xsd:complexType name="CheckIntegrityReturn">
                                       <xsd:sequence></xsd:sequence>
                                       </xsd:complexType>
                                    

So, after all this effort, can we get Axis to deliver a document/literal Web service? Well, WSDL2Java processes the composed WSDL without error, but at runtime:

  • Any XML attributes in a complex type are expressed in a returned instance as elements. This is because Axis—and JAX-RPC 1.0—don't support attributes. Check the generated Java classes.
  • Arrays are expressed as SOAP-encoded arrays, not as multiple-occurring elements, which literal usage requires.

Ah, but your struggle is not for naught. You now have a WSDL you can feed to any Web service platform.

WASP: Nothing special

WASP provides specialized scripts for installing to various J2EE (Java 2 Platform, Enterprise Edition) application servers or servlet containers, but this discussion focuses on using the standalone WASP Server. Also, WASP offers two deployment models: runtime publishing and persistent deployment. This discussion sticks with the latter.

Not surprisingly, in addition to a Java2WSDL utility, WASP provides its own WSDL2Java. However, you can bypass the WSDL middleman and follow a more streamlined server deployment path, provided that your service endpoint implementation class doesn't produce bogus bindings. There are two tools/steps:

  1. WASPPackager: Puts one or more Web services plus needed resources into a Web services "package." A package is literally a jar file, and should not be confused with a Java package.
  2. Deploy: With the WASP Server running, deploys the Web service package to the server.

Go back to the Outline Web service example and where a OutlineComponentImpl class implements the service endpoint. WASPPackager runs as follows:

waspRoot\bin\wasppackager.bat --package
                                                                              OutlinePackage 
                                                                              --output projectRoot\output\lib\OutlinePackage.jar 
                                                                              --service-name Outline 
                                                                              --class demo.outline.OutlineComponentImpl --force
                                                                              --uri /outline 
                                                                              --classpath classpathHere
                                                                          

Like WASP's Java2WSDL, WASPPackager takes --soap-binding-style and --soap-encoding-style options, whose default values are document and literal, respectively. Naturally, both tools also provide RPC and encoded choices for each option, respectively. WASP will allow any of the four combinations of binding style and use.

Taking this shortcut sacrifices some control that comes with utilizing an intermediate WSDL document using WASP's tools. To bring a WSDL into the Outline example means first running WASP's Java2WSDL just as was done in the Axis workaround, then appending the following argument to the WASPPackager invocation (changing nothing else):

--wsdl-file
                                                                              projectRoot\output\waspAutoSource\outline.wsdl
                                                                          

The burden is on the developer to ensure that the implementation class is consistent with the input WSDL. Specifying style and use with Java2WSDL obviates having to do so with WaspPackager.

All that remains is to start the WASP Server (via waspRoot\bin\serverstart.bat), and feed the archive that WASPPackager had as output as input to Deploy:

waspRoot\bin\deploy.bat --target http://localhost:6060 --redeploy
                                                                              projectRoot\output\lib\OutlinePackage.jar
                                                                          

Check the WASP documentation for how to include outside JARs and other classpath dependencies in a package JAR.

To start from a handcrafted WSDL, use WASP's WSDL2Java. For service source (or for client proxy source, for that matter), you have two basic choices with WSDL2Java, depending on the value of the --output-language argument:

  • java (default): Generate a service interface to be implemented
  • java-impl: Generate a skeleton implementation to be filled in

Here is a sample call:

waspRoot\bin\wsdl2java.bat
                                       
                                                                              --output-directory projectRoot\output\waspAutoSource
                                                                              --interface-package demo.outline
                                                                              projectRoot\source\xml\outline.wsdl
                                                                          

Compile the ensuing Java files and supply the classes and original WSDL to WASPPackager.

You can see that with WASP's tools, setting style and use is trivial. Indeed, for document/literal it's nothing. Still, you can also see that, with the verbosity of WASP's Java2WSDL, there's some usefulness to going to the trouble to write the WSDL document yourself. Ultimately, the only WSDL that counts is the one that a running server dynamically generates.

Wrapping up

While Axis and WASP can be integrated with full-fledged J2EE application servers, we could also extend this how-to to those application servers that have built-in Web services support. For example, BEA WebLogic Server 8.1, along with its Workshop development tool, also defaults to document/literal. WebLogic Server uses a wrapped code-level binding style.

To sum up, below is a list of the design decisions that show up with Web services at runtime. I've added a row for data protocol, where the typical answer will be SOAP 1.1. While it's all too easy to mistakenly lump certain decisions together with a given style and use combination, it should also be apparent that a certain choice at one point can restrict choices at other points.

  • Communication pattern: RPC; one-way messaging/notification; asynchronous callback
  • Transport: HTTP; SMTP (Simple Mail Transfer Protocol), JMS, or other mail-based protocol (if supported); other (if supported)
  • Data protocol: SOAP 1.1; SOAP 1.2 (if supported); direct use of HTTP GET and POST methods; returning non-SOAP XML (if supported)
  • Binding style: document; RPC
  • Use/encoding: literal; SOAP 1.1 Section 5 encoded
  • Code-level binding style: document; wrapped; message

In addition, there's the design decision whether to automatically generate or manually construct a working WSDL document.

But even for those developers who choose not to get their hands dirty crafting the SOAP XML, it should be evident that controlling the XML, even indirectly, can make for simpler Web service development. And potentially better Web services.

Mitch Gitman is currently working with Web services and XML Schema implementations for a major system and tools vendor. His other development efforts focus on J2EE/.Net integration and XML optimization. Previously, he worked as a Java server developer for a legacy integration vendor. After earning a BS in computer science in 1999 from the University of Arizona, Mitch migrated northwest in search of rain.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies