|
|
||
Marc Hadley's BlogMapping WADL to JavaPosted by mhadley on May 25, 2006 at 12:25 PM | Comments (0)In recent entries I've described the REST (or Web Style) oriented features of JAX-WS and touched on a new language, WADL, that aims to provide a description of Web style services. In this entry I'll bring together these two threads to show how a language like WADL can be used to generate strongly-typed client-side stubs layered on JAX-WS and JAXB. One of the key differences between Web-style and the style commonly associated with WS-* is the inversion of the balance between Web resources (something identified by a URI) and methods that can be applied to those resources. In the former style you often find a single URI (or a port in WSDL terminology) that exposes many custom methods described by a WSDL port type. In the Web-style you find many URIs, each of which supports a subset of a few standard HTTP methods. The WS-* style maps quite naturally to a single Java class/interface per WSDL port type that exposes Java methods corresponding to each WSDL method. This is the approach taken by JAX-WS which describes in detail how to map between a WSDL port type and a Java class/interface (see chapters 2 and 3). When considering Web-style however, the mapping to Java is less obvious but it seems reasonable to try to preserve the hierarchical nature of HTTP URIs while maintaining the mapping between a Web resource and a Java class/interface. There are a couple of candidate hierarchical structures in the Java language: packages and nested inner classes. Given that the relationship between resources isn't always obvious it seems prudent to avoid member classes which require an instance of the parent class for instantiation. That leaves packages or nested static member classes, I chose the latter after a fair bit of back-and-forth but I think either approach would work. Lets look at an example. The following WADL file describes the Yahoo! News Search service: <?xml version="1.0"?>
<application xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:yn="urn:yahoo:yn"
xmlns:ya="urn:yahoo:api"
xmlns="http://research.sun.com/wadl">
<grammars>
<include href="NewsSearchResponse.xsd"/>
<include href="NewsSearchError.xsd"/>
</grammars>
<resources base="http://api.search.yahoo.com/NewsSearchService/V1/">
<resource uri="newsSearch">
<method href="#search"/>
</resource>
</resources>
<method name="GET" id="search">
<request>
<query_variable name="appid" type="xsd:string" required="true"/>
<query_variable name="query" type="xsd:string" required="true"/>
<query_variable name="type" type="xsd:string"/>
<query_variable name="results" type="xsd:int"/>
<query_variable name="start" type="xsd:int"/>
<query_variable name="sort" type="xsd:string"/>
<query_variable name="language" type="xsd:string"/>
</request>
<response>
<representation mediaType="application/xml" element="yn:ResultSet"/>
<fault id="SearchError" status="400" mediaType="application/xml"
element="ya:Error"/>
</response>
</method>
</application>
The service actually supports a few more optional query parameters but I've omitted those to keep the length of the example down. The WADL file describes a single resource ( package com.yahoo.search;
public class Endpoint {
...
public static class NewsSearch {
public NewsSearch()
throws JAXBException
{
...
}
public ResultSet getAsResultSet(String appid, String query)
throws SearchError
{
...
}
public ResultSet getAsResultSet(String appid, String query, String type,
Integer results, Integer start, String sort, String language)
throws SearchError
{
...
}
}
}
I've omitted the implementation code as I want to concentrate on the structure of the generated code rather than implementation details. The first thing to note is the top level class Once an instance of Notice also that both methods throw package com.yahoo.search;
public class SearchError
extends Exception
{
protected Error m_faultInfo;
public SearchError(String message, Error faultInfo) {
super(message);
m_faultInfo = faultInfo;
}
public Error getFaultInfo() {
return m_faultInfo;
}
}
where Using this approach we can write client code for the Yahoo! News Search service as follows: Endpoint.NewsSearch s = new Endpoint.NewsSearch();
ResultSet results = s.getAsResultSet("jaxws_restful_sample", "java");
for (ResultType result: results.getResult()) {
System.out.println(result.getTitle()+" ("+result.getClickUrl()+")");
}
Hopefully you'll agree that this is a distinct improvement when compared to using JAX-WS and JAXB without code generation though, as is often the case, you sacrifice ultimate flexibility and increase the coupling between client and server as the price for such convenience. I'm currently working on an implementation of a WADL to Java command line tool and Ant plug-in using the techniques described above. Its currently still a prototype but it produces working code for a variety of interesting WADL feature combinations and I hope to release something people can play with soon. In the meantime, if you are interested in this kind of tooling and/or have a WADL file you'd like me to add to my test set then please email me at firstname.lastname@sun.com (substituting the relevant values). Bookmark blog post: CommentsComments are listed in date ascending order (oldest first) | Post Comment | ||
|
|