|
|
||
Marc Hadley's BlogCommunity: Java Web Services and XML ArchivesAnnouncing wadl.dev.java.netPosted by mhadley on September 29, 2006 at 12:31 PM | Permalink | Comments (3)I'm pleased to announce the formation of a new project on java.net for the development of WADL and associated tools: http://wadl.dev.java.net/. The goals of the project are spelled out here. I've primed the pump with an initial release of a tool that generates Java stubs for Web applications described using WADL. Also included is a sample application that demonstrates use of the tool with the Yahoo News Search Service. The code implements the ideas I blogged here but is still beta quality. I'm hoping public availability will help flush out the bugs and highlight areas that need more work. If you are interested in WADL and would like to help then please consider joining the project - there are many ways to contribute. WADL RevisionPosted by mhadley on August 03, 2006 at 07:43 AM | Permalink | Comments (2)In a previous entry I described some enhancements that were under consideration for an updated version of the WADL specification. The resulting updated WADL specification is now available along with the associated W3C XML Schema and RelaxNG Schema. In revising the specification I made a couple of breaking changes to simplify the language and improve clarity so this version of the specification uses a new XML namespace for the WADL elements. Here's what's new: Resource ReferencesAs previously described, Identification of LinksAs previously described, a DocumentationA <application xmlns="..." xmns:xhtml="...">
<doc xml:lang="en" title="Online widget catalogue">
<xhtml:p>An online widget catalogue for all your widgeting needs.</xhtml:p>
</doc>
<resources base="http://example.com/">
<doc xml:lang="en" title="Commercial widgets">
<xhtml:p>Widgets for the commercial sector.</xhtml:p>
</doc>
...
</resources>
</application>
Multiple sibling Resource ReworkA <resources base="http://example.com/">
<resource path="applications/widgets/{widgetId}">
...
</resource>
</resources>
The above extract describes a set of resources identified by the URIs conforming to the following template: http://example.com/applications/widgets/{widgetId}
Where Parameter ReworkThe The A new Future WorkWith these changes I'm now pretty happy with the base language but there remain a couple of things that still need more work:
I believe that both of the above can be addressed with non-breaking extensions to the language. WADL EnhancementsPosted by mhadley on June 30, 2006 at 01:07 PM | Permalink | Comments (5)In this entry I describe some of the language enhancements that will be in the next version of the WADL specification. These enhancements are the result of feedback I've received from other folks using the language and experience gained implementing a Java processor for WADL.
Resource ReferencesCurrently you can define a method or representation in one place and then include that definition by reference elsewhere. This is useful if the same representation is used in multiple method definitions or if the same method applies to more than one resource. Extending this capability to the <application>
<resources base="http://example.com/">
<resource href="stock">
<resource href="#widgets"/>
</resource>
<resource href="order">
<resource href="#widgets"/>
</resource>
</resources>
<resource id="widgets" path="widgets">
...
</resource>
</application>
Identification of LinksWhilst it would be possible at runtime to compare a URI embedded in a representation with the URIs of all of the resources in a WADL description to identify which resource it identifies, it would be preferable to be able to specify the resource targeted by a link up front where that information is known.
This is achieved in WADL by adding a new element to the language: E.g., if an application consists of the resources:
and a GET on the first resource gets me a <eg:WidgetList xmlns:eg="..."> <eg:Widget uri="http://example.com/widgets/xyzzy1"/> <eg:Widget uri="http://example.com/widgets/abccb1"/> ... </eg:WidgetList> such that <application xmlns:...>
<resources base="http://example.com/">
<resource uri="widgets">
<method href="#widgetList"/>
<resource id="widgetResource" uri="{widgetid}">
...
</resource>
</resource>
</resources>
<method name="GET" id="widgetList">
<response>
<representation mediaType="application/xml" element="eg:WidgetList">
<representation_variable path="/Widgets/Widget/@uri" repeating="true">
<link href="#widgetResource" rel="child" rev="index"/>
</representation_variable>
</representation>
</response>
</method>
</application>
The values of the DocumentationThe content model of WADL-defined elements is open for extension and I originally thought that documentation could be added by including html or xhtml elements within a WADL description. Thinking on this some more I've come to the conclusion that it would be better to define a standard <application>
<documentation><p>An online widget catalogue.</p></documentation>
<resources base="http://example.com/">
<documentation><p>Commercial widgets.</p></documentation>
...
</resources>
</application>
Multi-segment Resource PathsIts a pain to require multiple nested <resources base="http://example.com/">
<resource uri="applications/catalogues/widgets">
...
</resource>
</resources>
instead of <resources base="http://example.com/">
<resource uri="applications">
<resource uri="catalogues">
<resource uri="widgets">
...
</resource>
</resource>
</resource>
</resources>
Much more compact and readable ! Matrix URI SupportThe <resource uri="widgets"> <path_variable name="maxPrice" type="xsd:decimal" matrix="true"/> <path_variable name="minPrice" type="xsd:decimal" matrix="true"/> ... </resource> If the value of widgets;maxPrice=10.00;minPrice=5.00 A null value for a matrix path variable results in it being omitted from the uri. Still on the Drawing BoardOther enhancements still on the drawing board include:
Mapping WADL to JavaPosted by mhadley on May 25, 2006 at 12:25 PM | Permalink | 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). JAX-WS and Binary DataPosted by mhadley on April 27, 2006 at 07:24 AM | Permalink | Comments (2)In previous entries I've shown how to use the JAX-WS APIs to publish and use RESTful Web services. Up till now I've focussed mainly on XML/HTTP since this is what most services use but JAX-WS can also handle other kinds of data. This entry shows how to use the JAX-WS APIs to work with binary image data and uses the popular Flickr service to illustrate the capabilities. The Flickr APIs come in three varieties: REST, XML-RPC and SOAP. We'll concentrate on the REST API for this entry and develop some code that will search a particular users photo stream using keywords. Before you start developing your own application you'll need to obtain an API key from Flickr; API keys are free for non-commercial use, I'll include the one I obtained in the code below but please get a new key for any new applications you might develop. The initial boilerplate code is the same as shown in previous URI baseURI = new URI("http://www.flickr.com/");
URI staticBaseURI = new URI("http://static.flickr.com/");
QName serviceName = new QName("FlickrService", baseURI.toString());
Service flickrService = Service.create(serviceName);
QName flickrPortName = new QName("flickr_port",baseURI.toString());
URI address = new URI("http", null, baseURI.getHost(), baseURI.getPort(),
baseURI.getPath()+"services/rest/", null, null);
flickrService.addPort(flickrPortName, HTTPBinding.HTTP_BINDING, address.toString());
Dispatch<Source> flickrDispatch = flickrService.createDispatch(flickrPortName,
Source.class, Service.Mode.PAYLOAD);
The Flickr photo search method takes a user ID rather than a user name so we first have to call the find by username method to convert the human-friendly // set up the method call and parameters
Map<String, Object> requestContext = flickrDispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, "GET");
String queryString = "method=flickr.people.findByUsername" +
"&api_key=f2b38aa733c997301cd7153f05d15410" +
"&username=" + java.net.URLEncoder.encode(username, "utf-8");
requestContext.put(MessageContext.QUERY_STRING, queryString);
// execute query
Source result = flickrDispatch.invoke(null);
DOMResult domResult = new DOMResult();
Transformer trans = TransformerFactory.newInstance().newTransformer();
trans.transform(result, domResult);
// parse results
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
String userId = xp.evaluate("/rsp/user/@nsid", domResult.getNode());
With queryString = "method=flickr.photos.search" +
"&api_key=f2b38aa733c997301cd7153f05d15410" +
"&user_id=" + java.net.URLEncoder.encode(user, "utf-8") +
"&per_page=10" +
"&tags=" + java.net.URLEncoder.encode(tags, "utf-8");
requestContext.put(MessageContext.QUERY_STRING, queryString);
// execute query
result = flickrDispatch.invoke(null);
domResult = new DOMResult();
trans.transform(result, domResult);
// parse results
XPath xp = xpf.newXPath();
NodeList resultList = (NodeList)xp.evaluate("/rsp/photos/photo",
domResult.getNode(), XPathConstants.NODESET);
ArrayList<FlickrItem> list = new ArrayList<FlickrItem>();
for (int i=0;i<resultList.getLength();i++) {
String id = xp.evaluate("@id", resultList.item(i));
String title = xp.evaluate("@title", resultList.item(i));
String secret = xp.evaluate("@secret", resultList.item(i));
String server = xp.evaluate("@server", resultList.item(i));
FlickrItem item = new FlickrItem(staticBaseURI.toString(), id, server, secret, title);
list.add(item);
}
In the above I'm using a home-grown utility class public URL getMediumURL() {
return new URL(baseURI+server+"/"+id+"_"+secret+".jpg");
}
All of the above was really just a necessary precursor to get to what I really wanted to show: working with binary data using public Image getImage(FlickrItem item) {
URL url = item.getMediumURL();
Dispatch<DataSource> flickrStaticDispatch = flickrService.createDispatch(
flickrPortName, DataSource.class, Service.Mode.MESSAGE);
Map<String, Object> requestContext =
flickrStaticDispatch.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, new String("GET"));
requestContext.put(Dispatch.ENDPOINT_ADDRESS_PROPERTY, url.toString());
DataSource result = flickrStaticDispatch.invoke(null);
BufferedImage img = ImageIO.read(result.getInputStream());
return img;
}
Note the use of Its a simple matter of programming to take the above code and turn it into an application like that shown below. If you'd like to see this working alongside other code samples from previous entries then join me at JavaOne on Tuesday 16th May at 3.15pm for my session on JAX-WS and RESTful Web Services.
JAX-RPC 2.0 Early Draft 2Posted by mhadley on February 10, 2005 at 08:00 AM | Permalink | Comments (0)The JSR 224 Expert Group just published a second early draft of JAX-RPC 2.0. There's lots of new stuff in this draft so I'll just pull out some of the highlights here:
We still have some additional work to do before we issue a public draft, in particular we are currently working on:
Take a look and let us know what you think. Java Web Services Developer Pack 1.4 ReleasedPosted by mhadley on June 24, 2004 at 06:47 PM | Permalink | Comments (1)The latest version of the Java Web Services Developer Pack (version 1.4) is now available and offers support for both the WS-I Basic Profile 1.1 and WS-I Attachments Profile 1.0. Support for the WS-I attachments profile now allows interoperable description and exchange of SOAP messages that include attachments based on the WSDL 1.1 MIME binding and the SOAP Messages With Attachments specification. In addition, the Java WSDP 1.4 also includes a full implementation of the OASIS Web Services Security (WSS) standards that provide message-level security for SOAP. This allows messages to be sent and stored securely independent of transport or storage security measures. The Java WSDP 1.4 provides developer choice and flexibility by supporting deployement on the following containers: the Sun Java System Application Server Platform Edition 8, the Sun Java System Web Server 6.1, and Tomcat 5.0 for Java WSDP 1.4. The Java WSDP 1.4 and supported Web containers are all available for free download.
JAX-RPC 2.0 Early DraftPosted by mhadley on June 23, 2004 at 06:37 PM | Permalink | Comments (0)It looks like I've already been scooped by Eduardo but just in case you missed that, the first early draft of JAX-RPC 2.0 is now available for review. It addresses the following goals and requirements:
Of these, integration wih JAXB is the most significant departure from previous versions of JAX-RPC. Earlier versions defined their own mapping between XML and Java data structures but in JAX-RPC 2.0 all data binding functionality is delegated to JAXB 2.0 while JAX-RPC still handles mapping between Java and WSDL constructs. This separation of responsibilities allows a developer to resuse code between JAXB and JAX-RPC based applications or to easily extend an existing JAXB based application to use JAX-RPC facilities. It also provides JAX-RPC with full support for XML Schema where previously only a subset was required to be supported. Other significant additions inlcude a new document-centric API for dynamic Web service invocation, support for dynamic and type-safe client side asynchrony and several improvements to the handler framework including protocol agnostic handlers. This early draft is still a work in progress, subsequent versions of the specification will address the following additional goals and requirements:
The expert group solicits your input on the current draft, details of where to send comments are included in the specification. W3C charters new XML Binary Characterization Working GroupPosted by mhadley on April 05, 2004 at 09:04 AM | Permalink | Comments (0)Following the successful W3C Workshop on Binary Interchange of XML Information Item Sets hosted by Sun Microsystems last year, the W3C has now chartered a new XML Binary Characterization Working Group to further investigate this fascinating area. From the WG home page: "The XML Binary Characterization Working Group is tasked with gathering information about uses cases where the overhead of generating, parsing, transmitting, storing, or accessing XML-based data may be deemed too great for a particular application, characterizing the properties that XML provides as well as those that are required by the use cases, and establishing objective, shared measurements to help judge whether XML 1.x and alternate (binary) encodings provide the required properties." The charter runs for a year and has the following list of deliverables:
I'm pretty tied up with JAX-RPC 2.0 these days so I'm not going to be able to do much more than monitor this working group. Sign up now and have your say. Java Web Services Developer Pack (JWSDP) 1.3 ReleasedPosted by mhadley on October 21, 2003 at 08:53 AM | Permalink | Comments (0)The latest version of the Java Web Services Developer Pack (JWSDP) 1.3 has just been released, here's what's new:
W3C Announces Workshop on Binary Interchange of XML Information Item SetsPosted by mhadley on July 21, 2003 at 11:21 AM | Permalink | Comments (3)Use of XML as a format for exchange of information has its plusses and minuses. XML is self describing and lends itself to more loosely coupled information exchange but it is quite verbose and processing it can be resource intensive. As a result, the subject of a more compact/performant binary representation of XML has become a perma-thread in discussion fora such as xml_dev. In response to this interest, the W3C has announced a Workshop on Binary Interchange of XML Information Item Sets. My interest in this area is primarily its application to improving the performance of web services. Sun presented a technical session and BOF at the recent JavaONE conference describing the results of our investigations in this area as part of an internal project called 'Fast Web Services'. Fast web services uses ASN.1 to encode SOAP messages and other data described in XML Schema or WSDL in a very compact form and this work will form the basis of our position paper for the workshop. Hope to see you there ! | ||
|
|