|
|
||
Marc Hadley's BlogMarch 2006 ArchivesRESTful Web Service Endpoints in JAX-WSPosted by mhadley on March 21, 2006 at 11:05 AM | Permalink | Comments (2)In previous entries I've covered use of the client side JAX-WS A JAX-WS public interface Provider<T> {
public T invoke(T request);
}
You also have to pick the service mode in which the endpoint will operate and annotate the endpoint class to allow the JAX-WS runtime to identify the correct class to publish. Here's the start of our endpoint class (I'm going to interleave code and narrative but if you extract and stitch together the code segments below you'll end up with a complete class): @WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD)
public class SystemPropertiesProvider implements Provider<Source> {
@Resource
protected WebServiceContext context;
Arun has an informative blog entry that discusses the difference between PAYLOAD and MESSAGE mode and describes which types of The endpoint we'll develop here will allow a client to query the Java system properties of the endpoint implementation class, here is the implementation of the public Source invoke(Source source) {
Map<String, List<String>> query = getQueryParameters();
String replyData = getSystemInfoAsXML(query.get("property"));
StreamSource reply = new StreamSource(new StringReader(replyData));
return reply;
}
The protected Map<String, List<String>> getQueryParameters() {
MessageContext msgCtx = context.getMessageContext();
String queryString = (String)msgCtx.get(MessageContext.QUERY_STRING);
HashMap<String, List<String>> params =
new HashMap<String, List<String>>();
for (String s: queryString.split("&")) {
String[] keyVal = s.split("=");
try {
String key = URLDecoder.decode(keyVal[0], "UTF-8");
String val = URLDecoder.decode(keyVal[1], "UTF-8");
if (params.get(key) == null) {
ArrayList<String> list = new ArrayList<String>();
list.add(val);
params.put(key,list);
}
else {
ArrayList<String> list =
(ArrayList<String>)params.get(key);
list.add(val);
}
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
}
return params;
}
Its entirely possible that the above functionality already exists in some other class but, if it does, I didn't find it in the brief search I made. The protected String getSystemInfoAsXML(List The
If we wanted to deploy the endpoint in a Java EE container then the above is all the code needed. However, for this example, we'll use the new JAX-WS public static void main(String[] args) {
Endpoint e = Endpoint.create(HTTPBinding.HTTP_BINDING,
new SystemPropertiesProvider());
e.publish("http://127.0.0.1:8084/system/info");
System.out.println("Endpoint running");
try {
Thread.sleep(30000);
} catch (InterruptedException ex) {
}
e.stop();
System.out.println("Endpoint stopped");
}
}
In the above we publish the endpoint for 30 seconds and then stop it, you could also wait for a keypress in the main thread or use some other scheme to determine when to stop the endpoint. Now, stitch together the code segments from above, compile and run the class. Fire up a browser, point it to http://127.0.0.1:8084/system/info?property=os.version&property=os.name and see what OS the Java runtime thinks the endpoint is hosted on. Here's the XSL stylesheet that converts the XML document into a HTML table: <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html><body><table border="1">
<tr>
<th>Property</th>
<th>Value</th>
</tr>
<xsl:for-each select="/properties/property">
<tr>
<td>
<xsl:value-of select="@name"/>
</td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:for-each>
</table></body></html>
</xsl:template>
</xsl:stylesheet>
RESTful Web Services with JAX-WS and JAXBPosted by mhadley on March 08, 2006 at 11:44 AM | Permalink | Comments (1)In a previous blog entry I described how to use the dynamic client functionality of JAX-WS in combination with JAXP XPath capabilities to query a service providing data using XML/HTTP. In this entry I'd like to focus on how to use JAXB instead of XPath to get strongly typed access to the same data. To use JAXB we have to obtain an XML schema for the documents that will be exchanged. The documentation for the Yahoo News Search service includes a link to an XML schema for the results produced by the service. The JAXB tool time components transform an XML schema file into a set of Java classes that can be used to interact with an instance of a document that conforms to the schema. The JAXB runtime components take care of converting between the XML serialization of the data and its in-memory Java class equivalent. To integrate JAXB we have to run the
<property name="jaxb.home" value="/path/to/jwsdp-2.0/jaxb" />
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath>
<fileset dir="${jaxb.home}" includes="lib/*.jar" />
</classpath>
</taskdef>
<target name="-pre-compile">
<echo message="Compiling the schema..." />
<xjc schema="NewsSearchResponse.xsd" package="com.yahoo.search" target="gen-src">
<produces dir="gen-src/com/yahoo/search" includes="**/*.java" />
</xjc>
</target>
Note that the above will produce a new directory separate to the application source code. You'll need to edit the NetBeans project preferences to include this directory as a source code directory to ensure the generated code is compiled into the project. As before the first step in the application is to add a part for the Yahoo News Search service:
URI nsURI = new URI("urn:yahoo:yn");
QName serviceName = new QName("yahoo",nsURI.toString());
QName portName = new QName("yahoo_port",nsURI.toString());
Service s = Service.create(serviceName);
URI address = new URI("http", null, "api.search.yahoo.com", 80,
"/NewsSearchService/V1/newsSearch",
"appid=jaxws_restful_sample&type=all&results=10&sort=date&query=java",
null);
s.addPort(portName, HTTPBinding.HTTP_BINDING, address.toString());
As before, note that the URI constructed above contains a set of input parameters to the search service. The appid parameter identifies the application to Yahoo, if you are writing a new application you should register a new ID for it here. In this instance we are creating a URI that will search for news about Java and return at most 10 results sorted by date. Once the port is created we can use the Service instance to create a Dispatch instance:
JAXBContext jbc = JAXBContext.newInstance( "com.yahoo.search" );
Dispatch<Object> d = s.createDispatch(portName, jbc, Service.Mode.PAYLOAD);
Map<String, Object> requestContext = d.getRequestContext();
requestContext.put(MessageContext.HTTP_REQUEST_METHOD, new String("GET"));
Note the following differences in the code compared the previous version that used the XPath APIs:
Now that we have a
ResultSet rs = (ResultSet)d.invoke(null);
for (ResultType r: rs.getResult()) {
System.out.printf("%s: (%s)\n",r.getTitle(),r.getClickUrl());
}
The Unfortunately, due to a bug in the JAX-WS implementation included in JWSDP 2.0, the above code will not work and requires the following work-around. I'm told this is fixed in the latest builds but haven't confirmed that personally.
Unmarshaller u = jbc.createUnmarshaller();
ResultSet rs = (ResultSet)u.unmarshal((StreamSource)d.invoke(null));
for (ResultType r: rs.getResult()) {
System.out.printf("%s: (%s)\n",r.getTitle(),r.getClickUrl());
}
| ||
|
|