Write REST web service (JAX-RS)

Java API for RESTful Web Services (JAX-RS), is a set of APIs to develop a REST based web service. In this example, the JAX-RS service is created using Apache CXF (http://cxf.apache.org) framework. It is an open source services framework for developing services using JAX-WS and JAX-RS.



To get an basic understanding on JAX-RS, you can read [1] or JAX-RS API documentation. In the below tutorial, I will explain how to easily create a RESTful web service and a client using WSO2 Developer Studio.


Create a JAX-RS Project


Before creating a JAX-RS project,you should have setup WSO2 Developer Studio in your environment. If you are new to WSO2 Developer Studio, I recommend you to refer this link or download and setup WSO2 Developer Studio first.

Then click on the 'Developer Studio' menu in eclipse menu bar and then click on Open Dashboard. Click on 'JAX-RS Service Project' under Application Server in the dashboard. Then create a new JAX-RS Service. Enter Project, Package and Class names and click Finish. Class name should be the name of your main Service class. You may have to set Group ID, Version etc as well.

This is how my Project OrderProcessingService looks like. Note that you will have to add few external jars to your java build path such as cxf libraries, javax-ws-rs,apache-commons libraries. You may find them inside the lib folder of your WSO2 Application server distribution.

Write Service Code


The order processing service is capable of placing orders, add items, get items etc. This is a sample code of the OrderProcessingService class.


package org.wso2.jaxrs.sample;

import javax.ws.rs.*;
import javax.ws.rs.core.Response;

@Path("/orderprocessingservice/")
public class OrderProcessingService {
 private OrderItem[] items;
 
 public OrderProcessingService() {
  items = new OrderItem[10];
   init();
 }
 
 /**
  * Add items to the list
  * 
  * @param order
  * @return
  */
 @PUT
 @Path("/items/")
 public Response addItems(OrderItem order) {
  
  OrderItem oi = new OrderItem();
  oi.setItemCode(order.getItemCode());
  oi.setQuantity(items[order.getItemCode()].getQuantity()+ order.getQuantity());
  items[order.getItemCode()]= oi;
  
  return Response.ok().build();
 
 }
 
 /**
  * Place order with item code and required quantity
  */
 @POST
 @Path("/items/")
 public Response placeOrder(OrderItem order) {
  if (items[order.getItemCode()].getQuantity() >= order.getQuantity()) {
   OrderItem oi = new OrderItem();
   oi.setItemCode(order.getItemCode());
   oi.setQuantity(items[order.getItemCode()].getQuantity()-order.getQuantity());
   items[order.getItemCode()]= oi;
   return Response.ok(oi).build();
 
  } else
   return Response.noContent().build();
 
 }
 
 /**
  * Get availability of a given item
  */
 @GET
 @Path("/items/{id}/")
 public Response getItem(@PathParam("id") int id) {
  OrderItem o = items[id];
  return Response.status(200)
    .entity(o.getItemCode() + "," + o.getQuantity()).build();
   //return Response.ok(o).build();
 }
 
 final void init() {
  OrderItem o1 = new OrderItem();
  o1.setItemCode(0);
  o1.setQuantity(20);
  items[o1.getItemCode()] = o1;
 
  OrderItem o2 = new OrderItem();
  o2.setItemCode(1);
  o2.setQuantity(50);
  items[o2.getItemCode()] = o2;
  
  OrderItem o3 = new OrderItem();
  o3.setItemCode(2);
  o3.setQuantity(70);
  items[o3.getItemCode()] = o3;
 }
 
}

OrderItem.java class looks similar to this.

package org.wso2.jaxrs.sample;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "OrderItem")
public class OrderItem {

 private int itemCode;
  private int quantity;
  
  public int getItemCode() {
   return itemCode;
  }
  public void setItemCode(int itemCode) {
   this.itemCode = itemCode;
  }
  public int getQuantity() {
   return quantity;
  }
  public void setQuantity(int quantity) {
   this.quantity = quantity;
  }
}


Please look and understand the annotations used in both the classes with the references in [5] and [6].


Package and deploy


Once the code is ready, you will have to create a deployable .war file. Right click on the project and select 'Export Project as Deployable Archive' and select the destination.
Finally start the WSO2 Application server. (Refer download and install instructions if you do not know how to start a WSO2 server). WSO2 Application Server supports both JAX-RS as well as JAX-WS service deployments.

Login to the server (username/password:admin) and upload the created JAX-RS war file by clicking on JAX-RS/JAX-WS under applications in the navigator of the WSO2 Application Server Management Console. 




Once deployed, it will be listed under Running Applications with the name 
OrderProcessingService_1.0.0. Click on find services and see if the .wadl is created. Similar to the wsdl of a soap service, rest services are represented by wadl files. The wadl file should look like below.




Test the service


Following is a web service client that can be used to test this service. 

package main.java.demo.jaxrs.client;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Logger;

import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.resource.URIResolver;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.FileRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;

public class OrderProcessingClient {

 // private static final Logger log = Logger
 // .getLogger(OrderProcessingClient.class.getName());
 private static String SERVICE_URL = "http://10.100.5.100:9763/OrderProcessingService_1.0.0/services/order_processing_service/orderprocessingservice";

 public static void main(String args[]) throws Exception {
  // setting up for sending a GET request
  System.out.println("Sending HTTP GET request to getItem.");
  URL url = new URL(SERVICE_URL + "/items/1");
  URLConnection connection = url.openConnection();
  connection.setRequestProperty("accept", "text/xml");
  InputStream in = connection.getInputStream();
  System.out.println(url.toString());
  String[] output = getStringFromInputStream(in).split(",");

  int code = Integer.parseInt(output[0]);
  int quantity = Integer.parseInt(output[1]);
  System.out.println("Item Code: " + code + "  Quantity: " + quantity);
  System.out.println("\n\nSending HTTP PUT request to addItems.");
  // get the order item xml file.
  String inputFile = OrderProcessingClient.class.getResource("Add_Items.xml").getFile();
  URIResolver resolver = new URIResolver(inputFile);
  File input = new File(resolver.getURI());
  PutMethod put = new PutMethod(SERVICE_URL + "/items");
  RequestEntity entity = new FileRequestEntity(input,"text/xml; charset=ISO-8859-1");
  put.setRequestEntity(entity);

  HttpClient httpClient = new HttpClient();
  try {
   int result = httpClient.executeMethod(put);
   System.out.println("Response status code: " + result);
   System.out.println("Response body: ");
   System.out.println(put.getResponseBodyAsString());
  } finally {
   
   put.releaseConnection();
  }

  // setting up for sending a POST request
  System.out.println("\n\nSending HTTP POST request to placeOrder.");
  //
  // get the order item xml file.
  inputFile = OrderProcessingClient.class.getResource("Place_order.xml").getFile();
  resolver = new URIResolver(inputFile);
  input = new File(resolver.getURI());
  PostMethod post = new PostMethod(SERVICE_URL + "/items");
  post.addRequestHeader("accept", "text/xml");
  entity = new FileRequestEntity(input, "text/xml; charset=ISO-8859-1");
  post.setRequestEntity(entity);
  httpClient = new HttpClient();
  try {
   int result = httpClient.executeMethod(post);
   System.out.println("Response status code: " + result);
   System.out.println("Response body: ");
   System.out.println(post.getResponseBodyAsString());
  } finally {
   
   post.releaseConnection();
  }

 }

 private static String getStringFromInputStream(InputStream in) {
  CachedOutputStream bos = new CachedOutputStream();
  try {
   IOUtils.copy(in, bos);
   in.close();
   bos.close();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return bos.getOut().toString();
 }
}


For POST and PUT we can use following payloads (input.xml)

Add_Items.xml

<OrderItem> <itemCode>0</itemCode> <quantity>95</quantity> </OrderItem>

Place_Order.xml


<OrderItem> <itemCode>1</itemCode> <quantity>15</quantity> </OrderItem>


POST URL:

http://10.80.85.128:9764/orderProcessingService_1.0.0/services/order_processing_service/orderprocessingservice/items/

PUT URL:

http://10.80.85.128:9764/orderProcessingService_1.0.0/services/order_processing_service/orderprocessingservice/items/

GET URL:

http://10.80.85.128:9764/orderProcessingService_1.0.0/services/order_processing_service/orderprocessingservice/items/0


ESB REST API 

Going beyond, following is a sample REST API for ESB fronting this service.

    <api xmlns="http://ws.apache.org/ns/synapse" name="testAPI" context="/esb">
        <resource methods="POST DELETE PUT GET" url-mapping="/test">
            <inSequence>
                <log level="full">
                    <property name="PPPP" value="INCOMING"></property>
                </log>
                <call>
                    <endpoint>
                        <address uri="http://10.80.85.128:9764/orderProcessingService_1.0.0/services/order_processing_service/orderprocessingservice/items/0 format=rest"></address>
                    </endpoint>
                </call>
                <log level="full">
                    <property name="PPPP" value="PPPP"></property>
                </log>
            </inSequence>
            <outSequence>
                <log level="full"></log>
                <send></send>
            </outSequence>
        </resource>
    </api>




Hasitha Hiranya

No comments:

Post a Comment

Instagram