DatabaseRESTful WS with Jersey, Part 2

RESTful WS with Jersey, Part 2

This article further takes Part 1 of this article series to the realm of RESTful Web Services with Jersey. It contains almost no theoretical/conceptual background and delves directly into implementing one. Programmers often find implementing RESTful CRUD implementations that use EJB and ORM tools a daunting task. Here, I have tried to depict in pictorial detail the steps needed to create one. So, without further ado, let’s get our hands dirty.

Some Prerequisites

We’ll explore RESTful Web services with EJB and an ORM tool such an EclipseLink to represent data persistence. Because Tomcat 7/8 is not JEE compliant, we shall be using Glassfish 4.1 as the Application Server. The backend database would be MySQL with a JDBC type 4 driver. And, for all the required jar files, we shall depend on Maven (pom.xml). To sum up, the requirements list is as follows:

  • Java SDK 8
  • Netbeans 8.0.2 (bundled with Glassfish 4.1 + all we need for the project)
  • MySQL 5

1. Creating a Maven Project from the List of Archetypes

Open the NetBeans IDE. Create a New Project from the File menu.

Jersey1
Figure 1: Creating a new project

Select Jersey-quickstart-webapp from the list of known archetypes.

Jersey2
Figure 2: Selecting Jersey-quickstart-webapp

Next, provide the Project Name, Group ID, and Package. Finish.

Jersey3
Figure 3: Providing more information

A file named pom.xml will be created automatically; it contains a list of dependent jars. Maven will download a list of dependent jars behind the scenes. We need to add a few more dependencies to use EclipseLink and EJB in our project. So, the exact pom.xml file will as follows.

<project xmlns="http://maven.apache.org/POM/4.0.0"
   xmlns_xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi_schemaLocation="http://maven.apache.org/POM/4.0.0
   http://maven.apache.org/maven-v4_0_0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <groupId>org.mano.bookstore</groupId>
   <artifactId>bookstorerestapp</artifactId>
   <packaging>war</packaging>
   <version>1.0-SNAPSHOT</version>
   <name>bookstorerestapp</name>

   <build>
      <finalName>bookstorerestapp</finalName>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <inherited>true</inherited>
            <configuration>
               <source>1.7</source>
               <target>1.7</target>
            </configuration>
         </plugin>
      </plugins>
   </build>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.glassfish.jersey</groupId>
            <artifactId>jersey-bom</artifactId>
            <version>${jersey.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <dependencies>
      <dependency>
         <groupId>org.glassfish.jersey.containers</groupId>
         <artifactId>jersey-container-servlet-core</artifactId>
         <!-- use the following artifactId if you don't need -->
         <!-- servlet 2.x compatibility -->
         <!-- artifactId>jersey-container-servlet</artifactId -->
      </dependency>

      <dependency>
         <groupId>org.glassfish.jersey.media</groupId>
         <artifactId>jersey-media-moxy</artifactId>
      </dependency>
      <dependency>
         <groupId>org.eclipse.persistence</groupId>
         <artifactId>eclipselink</artifactId>
         <version>2.5.2</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>org.eclipse.persistence</groupId>
         <artifactId>org.eclipse.persistence.jpa.
            modelgen.processor</artifactId>
         <version>2.5.2</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.persistence</groupId>
         <artifactId>persistence-api</artifactId>
         <version>1.0</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>javax.transaction</groupId>
         <artifactId>jta</artifactId>
         <version>1.1</version>
         <scope>provided</scope>
      </dependency>
      <dependency>
         <groupId>org.hibernate.javax.persistence</groupId>
         <artifactId>hibernate-jpa-2.1-api</artifactId>
         <version>1.0.0.Final</version>
         <type>jar</type>
      </dependency>
      <dependency>
         <groupId>org.jboss.spec.javax.ejb</groupId>
         <artifactId>jboss-ejb-api_3.2_spec</artifactId>
         <version>1.0.0.Final</version>
         <type>jar</type>
      </dependency>
   </dependencies>
   <properties>
      <jersey.version>2.21.1</jersey.version>
      <project.build.sourceEncoding>UTF-8
         </project.build.sourceEncoding>
   </properties>
</project>

2. Table Structure for a MySQL Database

Create a rudimentary database and table SQL DDL. For more information on how to create a database and tables in MySQL, refer to the MySQL documentation.

CREATE DATABASE bookstore2;

CREATE TABLE books (
   ID INT NOT NULL,
   COPYRIGHT VARCHAR(255),
   EDITIONNUMBER INT,
   ISBN VARCHAR(255),
   PRICE DOUBLE,
   PUBLISHER VARCHAR(255),
   TITLE VARCHAR(255),
   PRIMARY KEY (ID)
) ENGINE=InnoDB;

3. Creating a Connection Pool and JNDI Resource in Glassfish

A Java EE application grants access to databases through the JDBC API. Creating a connection pool means that the data source is registered with the application server for use by the application running within the container. There may more than one data source available; hence the name connection pool. JNDI provides the name through which the JEE application gets hold of the data source in the container at runtime.

First, create a connection pool for the MySQL datasource as follows:s

  1. Start Glassfish server from NetBeans.
  2. Open the Administrative Console in the browser with the URL http://localhost:4848/common/index.jsf.
  3. Select JDBC, JDBC Connection Pools. and New….

Jersey04
Figure 4: The JDBC Connection Pools

In the General Settings, give a Pool Name with any name, such as MySQLPool, the Resource Type as javax.sql.DataSource, and choose Database Driver Vendor as MySql. Next.

Jersey05
Figure 5: Choosing a database driver

Now, provide the following additional properties name value pairs and then Save.

Encoding = UTF-8
User = user1
Password = password1
ServerName = mysql
DatabaseName = bookstore2
URL = jdbc:mysql://:3306/bookstore2
Url = jdbc:mysql://:3306/bookstore2

Once the JDBC Connection Pool settings are complete, go to JDBC Connection Pools, MySQLPool, and ping to check whether the setting are all right.

Jersey06
Figure 6: A ping was successful

Now to create the JDBC Resource, go to JDBC, JDBC Resource, New….

Jersey07
Figure 7: Creating a JDBC Resource

JNDI Name = bookstore2_jndi
Pool Name = MySQLPool (The pool you have created a while ago)

In the additional property section, add a new property:

DatabaseName = bookstore2

Save and close the browser. We are done creating the JDBC Connection Pool and JDBC Resources for our MySQL database.

4. Creating a Model Class

We primarily have one model class, one Book.java. Once the table has been created in the MySQL database, the NetBeans IDE provides a feature to automatically generate entity classes from database tables. Otherwise, they can be manually coded as follows.

Book.java

package org.mano.bookstore.bookstorerestapp.model;

import java.io.Serializable;
import java.util.Collection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@Table(name = "books")
@XmlRootElement
@NamedQueries({
   @NamedQuery(name = "Book.findAll",
      query = "SELECT b FROM Book b")
})
public class Book implements Serializable {
   private static final long serialVersionUID = 1L;
   @Id @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer id;
   private String copyright;
   private Integer editionnumber;
   private String isbn;
   private Double price;
   private String publisher;
   private String title;

   public Book() {
   }
   public Book(Integer id) {
      this.id = id;
   }
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public String getCopyright() {
      return copyright;
   }
   public void setCopyright(String copyright) {
      this.copyright = copyright;
   }
   public Integer getEditionnumber() {
      return editionnumber;
   }
   public void setEditionnumber(Integer editionnumber) {
       this.editionnumber = editionnumber;
   }
   public String getIsbn() {
      return isbn;
   }
   public void setIsbn(String isbn) {
      this.isbn = isbn;
   }
   public Double getPrice() {
      return price;
   }
   public void setPrice(Double price) {
      this.price = price;
   }
   public String getPublisher() {
      return publisher;
   }
   public void setPublisher(String publisher) {
      this.publisher = publisher;
   }
   public String getTitle() {
      return title;
   }
   public void setTitle(String title) {
      this.title = title;
   }
}

5. Creating EJB Classes

This class represents the business logic of the application and, in our case, the CRUD operations.

BookEJB.java

package org.mano.bookstore.bookstorerestapp.ejb;

import java.util.List;
importjavax.ejb.Stateless;
importjavax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
importjavax.persistence.TypedQuery;
importorg.mano.bookstore.bookstorerestapp.model.Book;

@Stateless
public class BookEJB {
   @PersistenceContext(unitName = "bookstore2PU")
   private EntityManager entityManager;
   public Book getBook(int id) {
      return entityManager.find(Book.class, id);
   }
   public List<Book> getBooks() {
      TypedQuery<Book> query =
         entityManager.createNamedQuery
         ("Book.findAll", Book.class);
      return query.getResultList();
   }
   public Book addNew(Book book) {
      entityManager.persist(book);
      return book;
   }
   public Book update(Book book) {
      Book b = entityManager.find(Book.class, book.getId());
      if (b != null) {
         entityManager.merge(book);
      }
      return book;
   }
   public Book delete(int id) {
      Book b = entityManager.find(Book.class, id);
      if (b != null) {
         entityManager.remove(b);
      }
      return b;
   }
}

6. Creating a RESTful Web Services Class

Let’s make a REST service class that exposes the CRUD APIs to the world.

BookWS.java

package org.mano.bookstore.bookstorerestapp.services;

import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import vjavax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.mano.bookstore.bookstorerestapp.ejb.BookEJB;
import org.mano.bookstore.bookstorerestapp.model.Book;

@Stateless
@Path("books")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class BookWS {

   @EJB
   private BookEJB bookEJB;

   @GET
   @Path("/{id}"
   public Book getBook(@PathParam("id") int id){
      return bookEJB.getBook(id);
   }

   @GET
   public List<Book> getBooks(){
      return bookEJB.getBooks();

   }

   @POST
   public Book addNew(Book book){
      return bookEJB.addNew(book);
   }

   @PUT
   @Path("/{id}")
   public Book update(@PathParam("id") int id,
         Book book){
      book.setId(id);
      return bookEJB.update(book);
   }

   @DELETE
   @Path("/{id}")
   public void delete(@PathParam("id") int id){
      bookEJB.delete(id);
   }
}

7. Using Postman as a RESTFul Client to Test CRUD APIs

Jersey08
Figure 8: Checking the GET request output that returns the list of Books in the database in JSON format

Now, let’s check the parametrized GET request that returns the Book with id = 2.

Jersey09
Figure 9: Checking the parameterized GET request

Jersey10
Figure 10: Inserting a new record into the database with POST

Jersey11
Figure 11: Updating an existing record with PUT

Jersey12
Figure 12: Deleting a record with DELETE

Jersey13
Figure 13: Confirming whether the record has been deleted with GET

Conclusion

These are some of the basic functionalities to implement CRUD operations in RESTful Web Services leveraging persistence with the help of an ORM tool and EJB. The main idea is to go hands-on rather than describing the underlying concepts of RESTful Web services. However, in doing so, I have only scratched the surface; interested readers may get started from here and explore further into the depth of APIs in the EE framework and RESTful Web Services.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories