Top Down or Bottom Up

When developing Java RPC-style web services, I'm torn whether to follow a top-down or bottom-up approach.

Using the bottom-up approach, you create your Java classes first and use the @WebService and @WebMethod annotations to specify that this is your web service interface. The WSDL for the service is generated automatically during the build (pretty nice). This approach has it's advantages in that you never have to leave Java to create the WSDL. Creating a WSDL file is not trivial and using this approach means you never need to think about the WSDL's <service>, <binding>, or <portType> elements and how they're linked together.

Conversely, a top-down approach means you create your WSDL first, then use a utility (either your IDE or a command line program) to generate the Java skeleton. Using this approach you need modify the generated Java stubs to call your business logic. If the interface (the WSDL) changes, you'll need to regenerate the classes, recreating your business calls.

On the surface, it appears the bottom up approach is the way to go. Changes to the web service API are effortless - you only need to update the Java class opposed to updating the WSDL and the Java program. So... what's the downside?

Expressiveness. Your web service is defined by it's API. It let's callers know exactly what's required as input and exactly what will be returned. Take a look as the following snippet from an XML schema I'm using to pass values back from a web service I created.
<xsd:complexType name="my_type">
<xsd:sequence>
<xsd:choice>
<xsd:element name="error_message" type="xsd:string"/>
<xsd:element name="values" type="xsd:float" minOccurs="1" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
This tells the caller, "I'm going to either give you an error message back or an array of floats. If I pass an array of floats, it will have at least 1 entry".

I'm not exactly sure how to best express this using Java classes. First of all, what's the best way to express the <choice> element in a Java class? There is no union data structure like there is in C++. Secondly, is there a Java collection that says "I must have at least 1 element"? Not that I know of.

Now there may be a way to generate the above XSD segment using the WSDL annotation tools, but I'm betting it's not trivial.

Assuming that I'm right, and creating the Java classes to generate the above XSD is not trivial. Let's create a simplified (almost equivalent) Java class and take a look at the WSDL generated from NetBeans for a web method return. Here are the class members for a Java class named MyType (in the class I also created the appropriate getters and setters).
   private String error_message;
private List<Float> values;
This type is returned by a @WebService @WebMethod defined in a Java class. And here is the corresponding XML schema defs generated by NetBeans.
<xs:complexType name="myType">
<xs:sequence>
<xs:element name="errorMessage" type="xs:string" minOccurs="0"></xs:element>
<xs:element name="values" type="xs:float" nillable="true" minOccurs="0" maxOccurs="unbounded"></xs:element>
</xs:sequence>
</xs:complexType>
While this schema is similar to the one above, it's less expressive in some important ways. In this case, the caller doesn't really know what to expect the service to return. It looks as if it could return nothing or both values (which isn't true). This ambiguity will cause clients of the service to overbuild - adding unnecessary logic to their systems to handle the empty message or the instance when both values are populated (neither of which will ever happen).

Since the API is the most important part of the web service - after all it's the contact between the provider and the client - I usually lean toward the top-down approach to building services. It's a little more involved for the provider, but by being more verbose and exact in it's usage it's more usable by the client - and that's the important part.

Comments

Popular posts from this blog

I Believe...

Performance Tuning JCAPS - Part 2

FRail :include