RESTful webservice using Jersey

Here I am going to give an example on how REST webservice works.

The most important concept in REST is resources, which are identified by global IDs — typically using URIs. Client applications use HTTP methods (GET/ POST/ PUT/ DELETE) to manipulate the resource or collection of resources. A RESTful Web service is implemented using HTTP and the principles of REST. Typically, a RESTful Web service should define the following aspects:

The base/root URI for the Web service such as http://<host>/<appcontext/contextpath>/<url pattern>/<resources>.
The MIME type of the response data supported, which are JSON/XML/TEXT/HTML etc.
The set of operations supported by the service. (for example, POST, GET, PUT or DELETE).

Methods

HTTP methods are mapped to CRUD (create, read, update and delete) actions for a resource. Although you can make slight modifications such as making the PUT method to be create or update, the basic patterns are listed as follows.

HTTP GET: Get/List/Retrieve an individual resource or a collection of resources.
HTTP POST: Create a new resource or resources.
HTTP PUT: Update an existing resource or collection of resources.
HTTP DELETE: Delete a resource or collection of resources.
Prerequisites

Eclipse, JDK 1.6, JAX-RS jars 1.8

1. create dynamic web project in Eclipse
2. Download JAX-RS for REST jar bundle and put the below jars into lib directory under WEB-INF/lib directory

REST webservice example using Jersey

3. Now create domain or model object for Book. Here I have put @XmlRootElement for easy marshalling and unmarshalling using JAXB.

package in.sblog.rest.model;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Book {
    private String id;
    private String title;
    private String author;
    private String description;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}

4. create singleton using enum for data provider because I am not using database here for CRUD operations.

package in.sblog.rest.dao;
import in.sblog.rest.model.Book;
import java.util.HashMap;
import java.util.Map;
public enum BookDao {
    INSTANCE;
    private Map<String, Book> booksMap = new HashMap<String, Book>();
    private BookDao() {
        Book book = new Book();
        book.setId("0001");
        book.setTitle("Java Example");
        book.setAuthor("Soumitra");
        book.setDescription("Love to learn Java");
        booksMap.put(book.getId(), book);
    }
    public Map<String, Book> getBookModel() {
        return booksMap;
    }
}

 
5. create BooksResource class for business logic.

Resource Class: class is a plain old java object (POJO) and is not restricted from implementing any interface. This adds many advantages such as reusability and simplicity.
Annotations: They are defined in javax.ws.rs.*, which are part of the JAX-RS (JSR 311) specification.
@Path: This defines the resource base URI. Formed with context root and hostname, the resource identifier will be something like http://localhost:8080/rest/service/books.
@GET: This means that the following method responds to the HTTP GET method.
@POST: This means that the following method responds to the HTTP POST method.
@Produces: Defines the response content MIME type such as plain/text,application/json,application/xml etc.

package in.sblog.rest.resources;
import in.sblog.rest.dao.BookDao;
import in.sblog.rest.model.Book;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
@Path("/books")
public class BooksResource {
    @Context
    UriInfo uriInfo;
    @GET
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public List<Book> getBooks() {
        List<Book> books = new ArrayList<Book>();
        books.addAll(BookDao.INSTANCE.getBookModel().values());
        return books;
    }
    @GET
    @Path("book/{id}")
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Book getBook(@PathParam("id") String id) {
        Book book = BookDao.INSTANCE.getBookModel().get(id);
        if (book == null) {
            throw new RuntimeException("Book not found for this Book Id: " + id);
        }
        return book;
    }
    @GET
    @Path("count")
    @Consumes(MediaType.TEXT_PLAIN)
    public String getCount() {
        int count = BookDao.INSTANCE.getBookModel().size();
        return String.valueOf(count);
    }
    @POST
    @Path("add")
    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response addBook(final Book book) {
        Response response;
        if (BookDao.INSTANCE.getBookModel().containsKey(book.getId())) {
            response = Response.noContent().build();
        } else {
            response = Response.created(uriInfo.getAbsolutePath()).build();
        }
        BookDao.INSTANCE.getBookModel().put(book.getId(), book);
        return response;
    }
}

6. You need to direct all the REST requests to the Jersey container by defining a servlet dispatcher in the application’s web.xml file. Along with the Jersey servlet, we need to also define an initialization parameter indicating the Java package that contains the resources.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>rest</display-name>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>in.sblog.rest.resources</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>
</web-app>

 
Now we need to test the REST service so create the following classes
7. Create Constant class which holds all the constants used in this application

package in.sblog.rest.utils;
public final class Constant {
    private Constant() {
        throw new InstantiationError("Error!");
    }
    public static String REST_BASE_URL = "http://localhost:8080/rest/service";
    public static String REST_BOOKS_URL = REST_BASE_URL + "/books";
    public static String REST_GET_BOOK_URL = REST_BOOKS_URL + "/book/";
    public static String REST_GET_COUNT_URL = REST_BOOKS_URL + "/count";
    public static String REST_ADD_NEW_BOOK_URL = REST_BOOKS_URL + "/add";
    public static String REST_ACCEPT_TEXT_PLAIN = "text/plain";
    public static String REST_ACCEPT_APPLICATION_XML = "application/xml";
    public static String REST_ACCEPT_APPLICATION_JSON = "application/json";
    public static String REST_REQ_ACCEPT_PROPERTY_KEY = "Accept";
    public static String REST_REQ_CONTENT_TYPE_PROPERTY_KEY = "Content-Type";
    public static String REST_METHOD_GET = "GET";
    public static String REST_METHOD_POST = "POST";
    public static int REST_RESP_HTTP_STATUS_OK = 200;
    public static int REST_RESP_HTTP_STATUS_CREATED = 201;
    public static int REST_RESP_HTTP_STATUS_EXISTS = 204;
}

 
8. Create java class with main method which invokes the REST services.

package in.sblog.rest.test;
import in.sblog.rest.model.Book;
import in.sblog.rest.utils.Constant;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.xml.bind.JAXBContext;
public class RestTest {
    public static void main(String[] args) {
        try {
            /**
             * get all Books
             */
            URL booksURL = new URL(Constant.REST_BOOKS_URL);
            HttpURLConnection booksConn = (HttpURLConnection) booksURL
                    .openConnection();
            booksConn.setRequestMethod(Constant.REST_METHOD_GET);
            // booksConn.setRequestProperty(Constant.REST_REQ_PROPERTY_KEY,
            // Constant.REST_ACCEPT_APPLICATION_JSON);
            booksConn.setRequestProperty(Constant.REST_REQ_ACCEPT_PROPERTY_KEY,
                    Constant.REST_ACCEPT_APPLICATION_XML);
            if (booksConn.getResponseCode() != Constant.REST_RESP_HTTP_STATUS_OK) {
                throw new RuntimeException("Failed! HTTP Error Code: "
                        + booksConn.getResponseCode());
            }
            BufferedReader brBooks = new BufferedReader(new InputStreamReader(
                    (booksConn.getInputStream())));
            String books;
            System.out.println("Books.... \n");
            while ((books = brBooks.readLine()) != null) {
                System.out.println(books);
            }
            booksConn.disconnect();
            /**
             * get total Books count
             */
            URL countURL = new URL(Constant.REST_GET_COUNT_URL);
            HttpURLConnection countConn = (HttpURLConnection) countURL
                    .openConnection();
            countConn.setRequestMethod(Constant.REST_METHOD_GET);
            countConn.setRequestProperty(Constant.REST_REQ_ACCEPT_PROPERTY_KEY,
                    Constant.REST_ACCEPT_TEXT_PLAIN);
            if (countConn.getResponseCode() != Constant.REST_RESP_HTTP_STATUS_OK) {
                throw new RuntimeException("Failed! HTTP Error Code: "
                        + booksConn.getResponseCode());
            }
            BufferedReader brCount = new BufferedReader(new InputStreamReader(
                    (countConn.getInputStream())));
            String count;
            System.out.println("Total Books.... \n");
            while ((count = brCount.readLine()) != null) {
                System.out.println(count);
            }
            countConn.disconnect();
            /**
             * get book details for a given book id
             */
            String id = "0001";
            URL bookURL = new URL(Constant.REST_GET_BOOK_URL + id);
            HttpURLConnection bookConn = (HttpURLConnection) bookURL
                    .openConnection();
            bookConn.setRequestMethod(Constant.REST_METHOD_GET);
            // bookConn.setRequestProperty(Constant.REST_REQ_PROPERTY_KEY,
            // Constant.REST_ACCEPT_APPLICATION_JSON);
            bookConn.setRequestProperty(Constant.REST_REQ_ACCEPT_PROPERTY_KEY,
                    Constant.REST_ACCEPT_APPLICATION_XML);
            if (bookConn.getResponseCode() != Constant.REST_RESP_HTTP_STATUS_OK) {
                throw new RuntimeException("Failed! HTTP Error Code: "
                        + bookConn.getResponseCode());
            }
            BufferedReader brBook = new BufferedReader(new InputStreamReader(
                    (bookConn.getInputStream())));
            String book;
            System.out.println("Book details.... \n");
            while ((book = brBook.readLine()) != null) {
                System.out.println(book);
            }
            bookConn.disconnect();
            /**
             * add new book
             */
            Book b = new Book();
            b.setId("0002");
            b.setTitle("REST Example");
            b.setAuthor("Soumitra");
            b.setDescription("REST Webservice");
            JAXBContext jaxbContext = JAXBContext.newInstance(Book.class);
            StringWriter stringWriter = new StringWriter();
            jaxbContext.createMarshaller().marshal(b, stringWriter);
            System.out.println("stringWriter: " + stringWriter);
            String input = stringWriter.toString();
            // String input =
            // "{\"id\":\"0003\",\"author\":\"Soumitra\",\"title\":\"REST Service\",\"description\":\"REST Webservice\"}";
            URL addBookURL = new URL(Constant.REST_ADD_NEW_BOOK_URL);
            HttpURLConnection addBookConn = (HttpURLConnection) addBookURL
                    .openConnection();
            addBookConn.setDoOutput(true);
            addBookConn.setRequestMethod(Constant.REST_METHOD_POST);
            addBookConn.setRequestProperty(
                    Constant.REST_REQ_CONTENT_TYPE_PROPERTY_KEY,
                    Constant.REST_ACCEPT_APPLICATION_XML);
            // addBookConn.setRequestProperty(
            // Constant.REST_REQ_CONTENT_TYPE_PROPERTY_KEY,
            // Constant.REST_ACCEPT_APPLICATION_JSON);
            OutputStream addBookOuput = addBookConn.getOutputStream();
            addBookOuput.write(input.getBytes());
            addBookOuput.flush();
            if (addBookConn.getResponseCode() == Constant.REST_RESP_HTTP_STATUS_EXISTS) {
                System.out.println("Content already exists!");
            } else if (addBookConn.getResponseCode() != Constant.REST_RESP_HTTP_STATUS_CREATED) {
                throw new RuntimeException("Failed! HTTP Error Code: "
                        + addBookConn.getResponseCode());
            } else {
                System.out.println("Book succesfully added.... \n");
            }
            addBookConn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 
That’s all. Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *