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.
RestService
This java class extends the HttpServlet and override service, doGet, and doPost methods.public class RestService extends HttpServlet { private String serviceName = "RestService"; // read this in init form init param public void service(HttpServletRequest request, HttpServletResponse response) throws &
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<String, Item> itemmap = new TreeMap<String, Item>(); 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 = (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 && "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 itemdispmap = new TreeMap(); 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("
"); pw.write("
"); for (Item it : itemdispmap.values()) { pw.write("- "); pw.write("
" + it.getId() + " "); pw.write("" + it.getName() + " "); pw.write("" + path + resource + "/" + it.getId() + " "); pw.write("" + it.getPrice() + " "); pw.write("
"); } pw.write("
"); } 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: RestService RestService service.RestService RestService /RestService/*
Test client
To test this POC framework, a jsp is written to act as client.<% 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(""); String datastr= null; while((datastr = rd.readLine())!=null) { stringbuffer.append(datastr); } stringbuffer.append("
"); if(wr != null) {wr.close();} if(rd != null) {rd.close();} if(conn != null) {conn.disconnect(); conn = null;} out.print(stringbuffer); out.print("
~~*~~ ~~*~~ ~~*~~
"); } %>
Create Read
UpdateDelete