Monday, May 08, 2006

RPC, Document, Bare, Wrapped, Literal- Get It Straight

It's something it's taken me time to fathom - just when, why and how do you
choose the SOAP Message format for your JAX-RPC web service?
The first choice is Document or RPC? For me, that's an easy one - if I'm using JAX-RPC then I probably care about standards, consistency, portability and interoperability. I'm probably going to use WS-I to check that services I create and use are WS-I Basic Profile compliant. I could use RPC/Literal but my SOAP message can't be entirely described by a schema so I'll discard that and stick to the Document style.
Now the more complicated part - made more so by the web services world changing the terms, finding better ways of expressing itself. Document style services send an XML document over SOAP. It's how they describe the <schema> that is a big differentiator.
Document/Bare (also know as Document/Literal) is considered by many to be the default and best method. It is simple, it takes a single method argument. Document/Wrapped wraps multiple arguments into one argument in the WSDL schema.
So consider the following method that adds a new address to an address book:

public boolean addEntry(Address address)

Using JDeveloper 10g to generate a Doc/Bare WSDL would give a <schema> element of:

<types>
<schema
...
<complexType name="Address">
<sequence>
<element name="streetName" type="string" nillable="true"/>
<element name="streetNum" type="int"/>
<element name="city" type="string" nillable="true"/>
</sequence>
</complexType>
<element name="addEntryElement" type="tns:Address" nillable="true"/>
<element name="addEntryResponseElement" type="boolean"/>
</schema>
</types>

A complexType Address has been created from the object type and is referenced in the addEntryElement. The addEntryResponseElement simply returns the method's boolean with no need to create a complexType to reference to.
Compare that with a Doc/Wrapped WSDL of the same method:

<types>
...
<complexType name="addEntry">
<sequence>
<element name="address" type="tns:Address" nillable="true"/>
</sequence>
</complexType>
<complexType name="Address">
<sequence>
<element name="streetName" type="string" nillable="true"/>
<element name="streetNum" type="int"/>
<element name="city" type="string" nillable="true"/>
</sequence>
</complexType>
<complexType name="addEntryResponse">
<sequence>
<element name="result" type="boolean"/>
</sequence>
</complexType>
<element name="addEntryElement" type="tns:addEntry"/>
<element name="addEntryResponseElement"type="tns:addEntryResponse"/>
</schema>
</types>

In this case there are 3 complexTypes: The complexType Address has been 'wrapped' inside a complexType addEntry. It is addEntry that is now referenced by addEntryElement. Plus a third complexType addEntryReponse has been created to hold the boolean response.
So it appears that the Doc/Wrapped form is more complicated - why do we need it? Well, it may be that you have existing code that you want to publish as a web service and these methods (or PL/SQL etc.) have multiple parameters. It may be that you don't want to go edit existing applications to create methods with a single argument or go to the bother of creating 'wrapper' methods with single arguments but want the web service to take care of that for you. This is a typical 'bottom-up' approach to web service development. Most tools use this as the default setting for creating services bottom-up
So continuing with the address theme, consider this method that creates an address object inside it:

public boolean addAddress(int sNum, String sName, String city)

This method could not be published as a Doc/Bare service but using the Doc/Wrapped approach you would finish up with:

<types>
...
<complexType name="addAddress">
<sequence>
<element name="sNum" type="int"/>
<element name="sName" type="string" nillable="true"/>
<element name="city" type="string" nillable="true"/>
</sequence>
</complexType>
<complexType name="addAddressResponse">
<sequence>
<element name="result" type="boolean"/>
</sequence>
</complexType>
<element name="addAddressElement" type="tns:addAddress"/>
<element name="addAddressResponseElement" type="tns:addAddressResponse"/>
</schema>
</types>

Although it might appear that this is very similar to the original Doc/Bare example (and it is!), except of course that it has a 2nd complexType for the boolean return, consider a method with arguments that were objects - each of those would be 'wrapped' in a complex type so the definition could get quite complicated.

So what's the conclusion? I wouldn't dream of saying that I had the definitive answer. But it certainly seems that Doc/Bare is preferable and simpler where practical. However, if a Java client proxy will be used to call your service then perhaps you might consider a Doc/Wrapped style as you can unpick the document of a doc/wrapped operation to get back the same parameter list easily. Confused? That's standards and choice for you.