Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Implementing a Representational State Transfer (REST) Framework

This article explains a proof of concept for implementing a REST framework using servlets.


advertisement
This is a continuation of my previous article about RESTful web services, "There is REST for the Weary Developer." This article explains a proof of concept for implementing a REST framework using servlets.

Overview

The proof of concept has one xsd, three Java classes, one jsp page, and web.xml as described below.
    * Item.xsd is modified to support multiple Item resources.
    * RestService java class extends HttpServlet
    * Item is java class for the resource
    * ItemResource java class provides CRUD (Create, Read, Update and Delete) methods for Item resource
    * Test is jsp page that act as client for testing the POC framework.
    * Web.xml configure the servlet to container
Explanations provided here are based on using websphere application server. The web application structure could be different based on the application server used.



Defining CRUD

The first step is defining CRUD (Create, Read, Update and Delete operations for the service.

The websphere application server does not support the PUT and DELETE methods for the HttpServlet. Though developers can implement these methods in HttpServlet, when the client send PUT and DELETE requests the websphere application server call POST and GET methods in HttpServlet respectively. In the above, table Update and Delete Operations are defined using the POST method.

Defining XSD

We have discussed before that the RESTful service considers information as resource and client, and that service communication is done by using XML over Http. The Item.xsd is enhanced to support multiple items so that when the client makes a request for all resources the server can list them in xml response.

<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xs:element name="Items"> <xs:complexType> <xs:sequence maxOccurs="unbounded"> <xs:element name="Item"> <xs:complexType> <xs:sequence> <xs:element name="Id" type="xs:string" minOccurs="0"/> <xs:element name="Name" type="xs:string"/> <xs:element name="Url" type="xs:string" minOccurs="0"/> <xs:element name="Price" type="xs:double"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

RestService

This java class extends the HttpServlet and override service, doGet, and doPost methods.

public class RestService &nbsp;extends HttpServlet { private String serviceName = "RestService"; // read this in init form init param public void service(HttpServletRequest request, HttpServletResponse response) throws &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&
nbsp;&nbsp;&nbsp;ServletException, IOException{
request.setAttribute("servicename", serviceName); super.service(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{ System.out.println("*****HttpServletRequest******** doGet() Method"); String pathinfo = request.getPathInfo(); if(pathinfo != null){ StringTokenizer stk = new StringTokenizer(pathinfo,"/"); if(stk.hasMoreTokens()){ String resourcename = stk.nextToken(); request.setAttribute("resource", resourcename); System.out.println("*****HttpServletRequest******** doGet() Method - resourcename: "+resourcename); //find resouce class and which method to call, from a config file // New we can use ItemResource if(stk.hasMoreTokens()){ String key = stk.nextToken(); request.setAttribute("key", key); } ItemResource.getInstance().getItems(request, response); } } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException{ System.out.println("*****HttpServletRequest******** doPost() Method"); String pathinfo = request.getPathInfo(); if(pathinfo != null){ StringTokenizer stk = new StringTokenizer(pathinfo,"/"); if(stk.hasMoreTokens()){ String resourcename = stk.nextToken(); System.out.println("*****HttpServletRequest******** doPost() Method - resourcename: "+resourcename); //find resouce and method from config file // New we can use ItemResource if(stk.hasMoreTokens()){ String key = stk.nextToken(); request.setAttribute("key", key); } if(stk.hasMoreTokens()){ String action = stk.nextToken(); request.setAttribute("action", action); } ItemResource.getInstance().manageItem(request, response); } } } }

The service method overrides the HttpServlet service method. And the servicename is set as a request attribute.

The doGet and doPost methods override the HttpServlet's doGet and doPost methods. The resource name (Item) and associated resource management class (ItemResource) are identified. The "key" attribute set to request which is the resource id in url "http://myserver:post/catalogapp /RestService/item/2" .

The DELETE operation is defined using the POST method. The POST method verifies the request to find whether the request is for Create, Update, or Delete. To indentify the POST request as the DELETE operation, an action letter "d" is included in CRUD definition.

Item

This Item java class represents a resource.

package resource; public class Item { private String Id; private String name; private double price; public Item(String id, String name, double price) { super(); Id = id; this.name = name; this.price = price; } public String getId() { return Id; } public void setId(String id) { Id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }

This class has Id, name, and price as properties.

ItemResource

The ItemResource class manages the Item as resource. This is a Singleton class.

package resource; public class ItemResource { private static ItemResource item = null; private int count = 0; private Map&amp;lt;String, Item&amp;gt; itemmap &amp;nbsp;= new TreeMap&amp;lt;String, Item&amp;gt;(); private ItemResource(){} public static ItemResource getInstance(){ if(item == null){ item = new ItemResource(); } return item; } public void manageItem(HttpServletRequest request, HttpServletResponse response) throws IOException{ // This method is for Create, Update and Delete StringBuffer sb = new StringBuffer(); BufferedReader r = request.getReader(); //read input and add to item map String line = null; while( (line=r.readLine()) != null){ System.out.println("ItemsResource:CreateItem() - line : "+line); sb.append(line); } r.close(); String key = (String)request.getAttribute("key"); String action &amp;nbsp;= (String)request.getAttribute("action"); if(key == null){ // its new item, add to resource map Item item = parseXml(sb.toString()); itemmap.put(item.getId(), item); } else { if(action != null &amp;amp;&amp;amp; "d".equalsIgnoreCase(action)){ // delete from map itemmap.remove(key); } if(action == null){ //update item in map Item item = parseXml(key,sb.toString()); itemmap.put(key, item); } } // return Success for now PrintWriter pw = response.getWriter(); pw.write("Success"); pw.close(); } public void getItems(HttpServletRequest request, HttpServletResponse response)
throws IOException{ //List the items String path = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+ request.getContextPath()+ request.getServletPath(); String resource =  "/" +request.getAttribute("resource"); // if pathinfo is null return all items, else retun specific item from itemmap. // implement here. PrintWriter pw = response.getWriter(); Map<String, Item> itemdispmap  = new TreeMap<String, Item>(); String key  = (String)request.getAttribute("key"); if(key == null){ itemdispmap = itemmap; } else { itemdispmap.put(key,itemmap.get(key)); } if (itemdispmap.size() > 0) { // may be jaxb can be use here pw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); pw.write("<Items>\n"); for (Item it : itemdispmap.values()) { pw.write("<Item>"); pw.write("<Id>" + it.getId() + "</Id>"); pw.write("<Name>" + it.getName() + "</Name>"); pw.write("<Url>" + path + resource + "/" + it.getId() + "</Url>"); pw.write("<Price>" + it.getPrice() + "</Price>"); pw.write("</Item>\n"); } pw.write("</Items>\n"); } pw.close(); } private Item parseXml(String str){ // write xml parser there. count++; return new Item(String.valueOf(count),"Pen", 3.14); } private Item parseXml(String key, String str){ // write xml parser there // this for update return new Item(key,"Pen", 3.20); } }

The manageItem method handles the Create, Update, and Delete operations. The getItems method lists the items managed as resources.

Web.xml

The servlet is configured in web.xml as following:

<servlet> <description></description> <display-name>RestService</display-name> <servlet-name>RestService</servlet-name> <servlet-class>service.RestService</servlet-class> </servlet> <servlet-mapping> <servlet-name>RestService</servlet-name> <url-pattern>/RestService/*</url-pattern> </servlet-mapping>

Test client

To test this POC framework, a jsp is written to act as client.

<html> <body> <% String submit = (String)request.getParameter("ops"); System.out.println("submit submit submit :"+submit); if(submit != null && ("post".equalsIgnoreCase(submit) || "put".equalsIgnoreCase(submit) || "delete".equalsIgnoreCase(submit))){ String xmlstr = (String)request.getParameter("item"); String urladdress = "http://"+request.getServerName()+":"+request.getServerPort()+ request.getContextPath()+"/RestService/item"; if("put".equalsIgnoreCase(submit)){ String id = (String)request.getParameter("id"); urladdress += "/"+id; } if("delete".equalsIgnoreCase(submit)){ String id = (String)request.getParameter("id"); System.out.println("delete id :"+id); urladdress += "/"+id+"/d"; xmlstr = ""; } java.net.URL url = new java.net.URL(urladdress); java.net.HttpURLConnection conn = (java.net.HttpURLConnection)url.openConnection(); conn.setRequestMethod("POST"); conn.setDoOutput(true); conn.setDoInput(true); java.io.OutputStreamWriter wr = new java.io.OutputStreamWriter(conn .getOutputStream()); wr.write( xmlstr.trim()); wr.flush(); wr.close(); wr = null; java.io.BufferedReader rd = new java.io.BufferedReader (new java.io.InputStreamReader(conn .getInputStream())); StringBuffer stringbuffer = new StringBuffer("<B>"); String datastr= null; while((datastr = rd.readLine())!=null) { stringbuffer.append(datastr); } stringbuffer.append("</B><br/>"); if(wr != null) {wr.close();} if(rd != null) {rd.close();} if(conn != null) {conn.disconnect(); conn = null;} out.print(stringbuffer); out.print("<br/> ~~*~~  ~~*~~  ~~*~~<br/>"); } %> <br/> Create <form  action="test.jsp" method="get"> New Item: <br/><textarea cols="100" rows="10" name="item"> <?xml version="1.0" encoding="UTF-8"?>
<Items xsi:noNamespaceSchemaLocation="http://myserver:port/catalogapp/RestService/item/xsd Item.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Item> <Name>Pen</Name> <Price>3.14</Price> </Item> </Items> </textarea><br/> <input type="submit" name="ops" value="Post"> </form> Read <form action="RestService/item" method="GET"> <!--  <input type="text" name="name" value="get ALL"/> -->
<input type="submit" name="ops" value="get All"> </form>
<form action="RestService/item/1" method="GET">
<!--  <input type="text" name="name" value="get 1"/> -->
<input type="submit" name="ops" value="get 1"> </form> Update <form  action="test.jsp" method="put">
Item:  <input type="text" name="id" value="1"/><br/>
Update Item: <br/><textarea cols="100" rows="10" name="item"> <?xml version="1.0" encoding="UTF-8"?>
<Items xsi:noNamespaceSchemaLocation="http://myserver:port/catalogapp/RestService/item/xsd Item.xsd"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Item> <Name>Pen</Name> <Price>3.20</Price> </Item> </Items> </textarea><br/> <input type="submit" name="ops" value="Put">
</form> Delete <form action="test.jsp" method="delete"> Item:  <input type="text" name="id" value="2"/><br/> <input type="submit" name="ops" value="Delete"> </form> </body> </html>

Deploying code

To use the code snippet in websphere application server, the following step might be useful.

Create a web application for servlet RestService. In the source directory create packages "resource" and "service". Copy Item.java and ItemReource.java to "resource" package and RestService.java to "service" package. Verify the web.xml for servlet definition. Copy test.jsp file to webcontent directory. Deploy the servlet to application and run test.jsp.

The jsp page will be displayed as the following:



   
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap