Developpez.com

Télécharger gratuitement le magazine des développeurs, le bimestriel des développeurs avec une sélection des meilleurs tutoriels

Developpez.com - Java
X

Choisissez d'abord la catégorieensuite la rubrique :


RESTful Web Services

Date de publication : 29 mai 2008

Par Nicolas Zozol (http://www.edupassion.com) (Blog)
 

This article explains how to use JSPs to fully dissect HTTP request in the objective to build an easy RESTful Web Service without any framework neither auto-genrerated code by an IDE.



Introduction

RESTful Web Services are a way to access to Ressources on Internet. Say you ask a server all documents written by User 54 : there is an infinity of ways for your browser to ask this ressource, and an infinity of correct responses by the server.
Programmers have written several standardized methods, and notably RPC, SOAP ou REST.
A web service deserves the mention "RESTful" if it gets most of the advices from Roy T. Fielding, inventor of REST.

Like other Web Services, data security is very important. Some will say that ressources in a SOAP service are highly secured because unreachables. Data security in a Stateless server will be described in another article.


I. Global Architecture


The Client sends a request to a JSP container (here :Tomcat 6.0.x). The JSP will forward the request URI, parameters and PostBody to the RessourceBean. The JSP will lead the work done by the JavaBean depending on the Http method used.

Notes :
A RessourceBean is a JavaBean implémenting functions setURI() et setPostBody().
The PostBody, unlike the QueryString, constitute parameters of the request that we can't see in the URL.

II. Recovering request datas


II-1. Recovering parameters

It's the easy and classic part : let's have a request PUT /wsxseditor/service/document/document.jsp?dataBaseId=24&title=ChangeTheTitle We need to add to the JSP :

<jsp:useBean id="bean" class="bean.DocumentBean" scope="request"/>
<jsp:setProperty name="bean" property="*"/>
The DocumentBean must implement setDataBaseId() and setTitle() functions.


II-2. Recovering request URI

Each JSP can deal with the HttpServletRequest object using ${pageContext.request}. We add to the JSP :

<jsp:setProperty name="bean" property="URI" value="${pageContext.request.requestURI}"/>
DocumentBean must now implement interface RessourceBean, ou at least the setURI() function.


II-C. Recovering request PostBody

Here is a POST request as seen in the sniffer Wireshark. Note that a POST request can have a QueryString, wich can be useful to the algorithme in your RessourceBean.


In this classic exemple, I create a new element in my document. This element is represented in XML in the PostBody, and I use the QueryString parameters fatherId et brotherId to know where to place the element in the document. But recovering the PostBody is more delicate, because we must work with Java Streams.

<%
java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(request.getInputStream()));

String line,result="";
while ((line = br.readLine()) != null) {
    result+=line;
}
br.close();
bean.setPostBody(result);
%>
DocumentBean must implement the interface RessourceBean, or at least a setPostBody ( ) function.


III. Dealing with different Http methods

Using correctly Http methods GET (Read), POST (Create), PUT (Update) et DELETE (Delete) is in my opinion THE fundamental aspect of a RESTful Web Service. To know which method has been used by the request, we must ask once again to the HttpServletRequest :

<c:if test="${pageContext.request.method=='POST' }">
    <c:choose>
        <c:when test="${bean.createOK}">
        ... some xml ...
        </c:when>
        <c:otherwise>
        ... some xml ...
        </c:otherwise>    
    </c:choose>
</c:if>

<c:if test="${ pageContext.request.method == 'PUT' }">
    <c:choose>
        <c:when test="${bean.updateOK}">
        ... some xml ...
        </c:when>
        <c:otherwise>
        ... some xml ...
        </c:otherwise>    
    </c:choose>
</c:if>
The RessourceBean will implement, depending on possibilities given by the Web Service, isReadOK(), isCreateOK(), is UpdateOK(), isDeleteOK() functions.


IV. Analyser les URI


IV-1. Objectives

We have started the article with the request : PUT /wsxseditor/service/document/document.jsp?dataBaseId=24&title=ChangeTheTitle. We would like now a more sexy request like this one : PUT /wsxseditor/document/24?title=ChangeTheTitle

URL rewriting is less important than correct use of Http methods, but it will promote exchanges of URLs between different web pages and so Connectivity. Sexy URLs will also, unlike SOAP, allow to understand in one look the meaning of the request and help so maintainability.


IV-2. Servlet-Mapping

It's easy with Netbeans to forward the request /wsxseditor/document/24 to the JSP /wsxseditor/service/document/document.jsp. Double-click on the file web.xml, and fill the form :

web.xml
web.xml
The web.xml file will look like :

<?xml version="1.0" encoding="UTF-8"?>
<web-app ...>
<servlet>
    <servlet-name>UriAdaptor</servlet-name>
    <jsp-file>/service/document/document.jsp</jsp-file>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>UriAdaptor</servlet-name>
    <url-pattern>/document/*</url-pattern>
</servlet-mapping>
</web-app>
Because the dataBaseId parameter has disappeared, we must say to the RessourceBean that the number 24 represents the dataBaseId.


IV-3. URI Analyse

The ResourceBean implements the setURI () function. When we'll transmit the URI to the bean, we will also decode this URI :

public void setUri(String uri) throws NotFoundException {
   this.uri = uri;
   robusta.rest.j2ee.UrlDecoder decoder=new robusta.rest.j2ee.UrlDecoder();
   this.dataBaseId=decoder.firstNumber(uri);
}
UrlDecoder.firstNumber() is a fonction from my Robusta Toolbox that uses regular expressions to detect the first number of the URI. You'll find the source code at this adress.


V. Elegance with a JSP Tag

JSP scripts ( <% java code %> ) are not easily readable and, what is worst, promote copy/paste of the source code. But we can use a simple, non-intrusive tag JSP to resolve this problem.
Here is the robusta.tag file in the directory web/WEB-INF/tags :

<%@tag description="Conciliate RESTful Web Services and JSPs" pageEncoding="UTF-8"%>

<%@attribute name="method"%>
<%@attribute name="ressource" rtexprvalue="true" type="base.RessourceBean" required="true"%>
<%@attribute name="request" rtexprvalue="true" type="javax.servlet.http.HttpServletRequest" required="true"%>

<%
java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(request.getInputStream()));

String line,result="";
while ((line = br.readLine()) != null) {
    result+=line;
}
br.close();

ressource.setPostRequest(result);
ressource.setURI(request.getRequestURI());
this.method=request.getMethod();
%>
The tag will need the RessourceBean and the HttpServletRequest, then create the variable method. The JSP will finally looks like :

<%@ taglib tagdir="/WEB-INF/tags/" prefix="ws" %>
<jsp:useBean id="bean" class="bean.uriBean" scope="request"/>
<jsp:setProperty name="bean" property="*"/>

<ws:robusta ressource="${bean}" request="${pageContext.request}"/>

<c:if test="${method == 'POST' }">
... some xml ...
</c:if>
warning Your bean must implements the RessourceBean interface.

Conclusion

Using theses technics has a huge advantage against classics Servlets : it avoids awfull out.println("\"He I am\" said Chuck"); and works with URIs, PostBody and Http methods much more easily than with standard Servlets. The JSP will be perfect to exchange XML datas with the Ajax Client.

JSF can do the same job, but is slower and more complicated to learn. Moreover JSF is designed to be part of the graphical layer, and that will not help you much with your web service. And nowadays, graphical layer is more often delagated to the Ajax client.

The picture in the request from WireShark shows a cookie that defines the session in the server : it's against principe of Stateless request, what is not the subject of the article. We'll explain in further articles why and how to create a full stateless web serice with at least an equal security.



Valid XHTML 1.1!Valid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Nicolas Zozol. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Responsables bénévoles de la rubrique Java : Mickael Baron - Robin56 -