XForms backed with JAX-RS RESTful services

December 31st, 2009 by Henri Bezemer

In an earlier post I presented a simple example of a login form implemented with XForms. In this example, XML data submitted by the form is parsed by a Java Servlet into a DOM tree, data is extracted using XPath and finally the servlet directly prints a XML result to its response stream. For large scale development, this is not the most efficient and safe way to implement this functionality.

JAX-RS allows us to efficiently build RESTful services, which are a perfect match to XForms. In this post I’ll present a JAX-RS service to replace the servlet from the login form example.

Marshalling XML

RESTful services can produce and consume any kind of content, however in this case its XML content that we’re after. JAXB is leveraged to marshal the XML. The data received from and replied to the form are in a particular namespace. There are various ways to deal with namespaces in JAX-B, but I prefer the package level solution, because then I don’t have to repeat anything. Package level annotation must be placed in a special file called package-info.java. Here is its contents:

@javax.xml.bind.annotation.XmlSchema(namespace="http://www.zienit.com/login",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.zienit.simplerest;

Next is a class Login which is able to marshal the XML data that will be sent to the service:

package com.zienit.simplerest;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="login")
public class Login {
	@XmlElement public String user;
	@XmlElement public String password;
}

This code is pretty much self explanatory. Note that because of the package level definition elementFormDefault = qualified, the namespace is also in effect for the elements user and password, as required by the specific XML definition. Finally, here is the class Outcome that will be used to reply XML data back to the form:

package com.zienit.simplerest;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;

@XmlRootElement(name="outcome")
public class Outcome {
	@XmlValue public String value;
}

The service

The RESTful service itself is very simple:

package com.zienit.simplerest;

import javax.ws.rs.*;

@Path("/loginservice")
public class LoginService {

	@POST
	@Consumes("application/xml")
	@Produces("application/xml")
	public Outcome login(Login l) {
		Outcome o = new Outcome();
		o.value = "password-incorrect";
		if ("expire".equals(l.password)) {
			o.value = "password-expired";
		} else if ("hacker".equals(l.user)) {
			o.value = "password-permanently-blocked";
		} else if (l.user.equals(l.password)) {
			o.value = "success";
		}
		return o;
	}
}

Note that besides a few JAX-RS annotations, this Java code contains pure business logic (not very useful business logic in this particular example). Refer to the previous post about JAX-RS for a Maven POM. Note that for the code to compile you need to add a extra dependency on JAXB:

<dependency>
	<groupId>javax.xml.bind</groupId>
	<artifactId>jaxb-api</artifactId>
	<version>2.1</version>
	<scope>provided</scope>
</dependency>

REST in action

After you’ve deployed the RESTful service to GlassFish, you can run the form (I simply load the form in my browser using a file: url). Using the free tool tcptrace, I’ve traced the following HTTP traffic going on between the form and the service:

POST /simplerest/loginservice HTTP/1.1
Accept: */*
Accept-Language: en-us
Content-Type: application/xml
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6.3; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
Host: localhost:8081
Content-Length: 91
Connection: Keep-Alive
Cache-Control: no-cache

<login xmlns="http://www.zienit.com/login"><user>foo</user><password>foo</password></login>

 

HTTP/1.1 200 OK
X-Powered-By: Servlet/2.5
Server: Sun GlassFish Enterprise Server v2.1
Content-Type: application/xml
Content-Length: 117
Date: Thu, 31 Dec 2009 10:09:04 GMT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><outcome xmlns="http://www.zienit.com/login">success</outcome>

While this example is still simple, I think that JAX-RS really shows its potential here!

No Comments

Comments are closed.