Wednesday, February 24, 2010

JAX-WS RESTful web services

Publishing a Restful web service with JAX-WS starts by implementing the javax.xml.ws.Provider<T> interface. Implementations are required to support Provider<Source> and Provider<SOAPMessage>. The ServiceMode annotation can be used to control whether the Provider instance will receive entire protocol messages or just message payloads.

Here we are going to look at an example which accepts search consumer request and results the particular consumer details.

So our service will look like
public class ConsumerSearchService implements Provider<Source>{
}

The next step is to declare a @Resource annotation that will be used by the JAX-WS runtime to inject a WebServiceContext into our ConsumerSearchService instance.

public class ConsumerSearchService implements Provider<Source>{
@javax.annotation.Resource(type=Object.class)
protected static WebServiceContext wsContext;
}

Here we use JAXB for marshall and unmarshall the xml request and response objects.
So the next step is to create JAXBContext in the constructor of our service class.


public class ConsumerSearchService implements Provider<Source>{
@javax.annotation.Resource(type=Object.class)
protected static WebServiceContext wsContext;
private JAXBContext jc;
public ConsumerSearchService () {
    try {
       jc = JAXBContext.newInstance("consumer.rest");
    } catch(JAXBException je) {
       System.out.println("Exception " + je);
       throw new WebServiceException("Cannot create JAXBContext", je);
    }
    }
}

The next step is to implement Source Provider<Source>.invoke (Source source)

public Source invoke(Source source) {
try{
    MessageContext mc = wsContext.getMessageContext();
    String path = (String)mc.get(MessageContext.PATH_INFO);
    String method = (String)mc.get(MessageContext.HTTP_REQUEST_METHOD);
    System.out.println("Got HTTP "+method+" request for "+path);
    if (method.equals("POST"))
        return handlePost(source, mc);
    throw new WebServiceException("Unsupported method:" +method);
} catch(JAXBException je) {
   throw new WebServiceException(je);
}
}

If you look at API documentation of MessageContext it says, javax.xml.ws.handler.MessageContext interface provides methods to manage a property set. MessageContext properties enable handlers in a handler chain to share processing related state.

From MessageContext.HTTP_REQUEST_METHOD we get HTTP method and we can handle all other methods(GET, PUT, DELETE) similarly as POST method handled above.

Next we will look at the implementation of handlePost (source, mc) method.
/**
* Handles HTTP POST.
*/
private Source handlePost (Source source, MessageContext mc)
throws JAXBException {
mc.put(MessageContext.HTTP_RESPONSE_CODE, 201);
Unmarshaller u = jc.createUnmarshaller();
ConsumerReq request = (ConsumerReq) u.unmarshal(source);
ConsumerRes response = searchConsumer(request);
return new JAXBSource(jc, response);
}

Deployment
We are going to look at deploying same service in two different environments. One is IBM specific where you can deploy the war file in Web sphere without any sun specific configurations. The other one if sun specific.

1. IBM Specific

@javax.xml.ws.WebServiceProvider(
serviceName="ConsumerSearchService",
portName="ConsumerSearchServicePort",
targetNamespace=http://consumer.details.com/v1)

By placing the above annotation statement on top of the web service class is enough to deploy the web service in web sphere.

2. Sun Specific

To deploy our endpoint on a servler container we need to make configuration changes in two files. One is in web.xml and other is to create or modify sun-jaxws.xml.

The following entries in web.xml for above example.
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<listener>
<listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener>
<servlet>
<servlet-name>ConsumerSearch</servlet-name>
<servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ConsumerSearch</servlet-name>
<url-pattern>/ConsumerSearchService/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>

Next we add a sun-jaxws.xml deployment descriptor to the WAR file. The following is an example.
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="ConsumerSearchService"
implementation="ConsumerSearchService"
binding="http://www.w3.org/2004/08/wsdl/http"
url-pattern='/ConsumerSearchService/*'/>
</endpoints>

No comments:

Post a Comment