Build REST resources using Apache Wink and OpenJPA

Apache Wink is a framework for building RESTful web services. In this article, see how to use Wink and OpenJPA (Java Persistence Architecture) to implement, store, retrieve, and update a resource. Also, learn to make resources persistent using OpenJPA. Article examples show how the CRUD (create, retrieve, update, and delete) operations can be completed end to end using Wink and OpenJPA.

Sathish Maiya, Staff Software Engineer, IBM

Sathish Maiya photoSathish Maiya, a staff software engineer at IBM, is with the Websphere Partner Gateway Group. Sathish has an engineering degree in computer science engineering from Mysore University, India, and holds a master's degree in biomedical engineering from Mangalore University, India. He has experience in software design, development, and testing.



Anish Chaube, Software Engineer, IBM

Anish Chaube photoAnish is an associate software engineer at IBM and is currently with the Websphere Partner Gateway Group. He holds a master's degree in information technology from the International Institute of Information Technology, Bangalore. Anish has experience in software development and testing.



Pranab K Das, Software Engineer, IBM

Pranab Das photoPranab Das is a software engineer with the WebSphere Partner Gateway Group at the IBM Software Labs in India. He has a bachelor's degree in computer science from Banaras Hindu University. Pranab has experience in software development and testing.



Dilip Sathyanarayan, Software Engineer, IBM

Dilip SathyanarayanDilip Sathyanarayan, a senior software engineer at IBM, has experience in software development, testing, automation testing, and technical documentation. Dilip is currently pursuing a master's degree in information systems at Marist College in New York.



29 November 2011

Also available in Chinese Japanese

Introduction

Representational state transfer (REST) is a style of software architecture for distributed hypermedia systems, such as the World Wide Web. Resources, or sources of specific information, are an important part of REST. Each resource is referenced with a global identifier (for example, a URI in HTTP). To manipulate resources, components of the network—called user agents and origin servers—communicate using a standardized interface (HTTP) and exchange representations of the resources.

Frequently used abbreviations

  • CRUD: Create, retrieve, update, delete
  • HTTP: HyperText Transfer Protocol
  • REST: Representational state transfer
  • URI: Universal Resource Identifier
  • XML: EXtensible Markup Language

Apache Wink is a framework that you can use for building RESTful web services. Wink facilitates the development and consumption of REST web services by providing the means for modeling the service according to the REST architectural style. Wink provides the necessary infrastructure for defining and implementing the resources, representations, and uniform methods that comprise a service. The Apache OpenJPA framework is open source software that defines how the persistence can be achieved for an object.

In this article, use Wink and OpenJPA to implement HTTP operations on resources through a REST service. Learn about modeling, URI design, and using Wink annotations to implement create, retrieve, update, and delete (CRUD) operations on a sample resource.

You can download the source code used in this article.

Resource modeling

Every resource must be modeled into a particular structure, such as XML or JSON. All the attributes and values of the resource will be mapped correspondingly with XML attribute names and values. As an example for this article, let's consider "Employee" as a resource. Each Employee has unique attributes, such as employee ID, employee name, employee address, employee email, and employee telephone number. Listing 1 shows the XML structure of the Employee resource.

Listing 1. XML structure of the Employee resource
<employee>		
     <employeeId>101</employeeId>
     <employeeName>employee Name</employeeName>
     <address>XYZ C Block, Bangalore-560025</address>
     <email>employee email</email>
     <telephone>5551234567</telephone>
</employee>

The Apache Wink framework supports JAXB annotations to marshall and unmarshall XML or JSON in to a Java object, and vice versa. OpenJPA provides a framework for persistence of Java objects into a relational data store.


Entity modeling

Entities in OpenJPA are persistence objects that represent datastore records. For the example in this article, _Employee is the entity model that represents the Employee object. Each persistence instance of the entity class _Employee represents a unique datastore record (a unique employee). You use annotations to define the entity model. In the case of Employee, @Table (name="CF_EMPLOYEE") is used for defining the Employee entity.

All entity classes must declare one or more fields that together form the persistent identity of an instance. In the case of our example employee, employeeId is used as the unique identifier. OpenJPA uses the version field in entities to detect concurrent modifications to the same datastore record. Use the @Version annotation. The code excerpt in Listing 2 shows how to create an entity model for the Employee resource.

Listing 2. OpenJPA model for Employee resource
package openJpa.model;

/**
 * Persistent Class for Employee
 * OpenJPA enables writing persistent classes in a very transparent way
 */

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
/*Each entity represents a relational datastore record.
In this code all employee records will be stored in a table called CF_EMPLOYEE */
@Table(name="CF_EMPLOYEE")
/*
Databases allow Native sequences to be created , which are database
structures that generates increasing numeric values.
SequenceGenerator annotation represents a named database Sequence
*/
@SequenceGenerator(name="employeeSeqGen", sequenceName="native(Sequence=CF_EMPLOYEE_SEQ)")
public class _Employee implements Serializable {
	
	private static final long serialVersionUID = 1L;
	public _Employee() {
		super();
	}
	
/*All entity classes must declare one or more fields which together 
forms the persistent identity of an instance.Every employee will have an
unique employeeID which is the persistent identity */
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="employeeSeqGen")
	private int employeeId;
/* OPEN JPA uses version field in entities to detect concurrent 
modifications to the same datastore record.Version field is optional
for any entity, but without one concurrent threads or processes might succeed
in making conflicting changes to the same record at the same time. */

	@Version
	private int version;
	
	private String employeeName;
	private String address;
	private String email;
	private int telephone;
	
	public void setEmployeeId(int employeeId) {
		this.employeeId = employeeId;
	}
	public int getEmployeeId() {
		return employeeId;
	}
	public void setVersion(int version) {
		this.version = version;
	}
	public int getVersion() {
		return version;
	}
	public void setEmployeeName(String employeeName) {
		this.employeeName = employeeName;
	}
	public String getEmployeeName() {
		return employeeName;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getAddress() {
		return address;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getEmail() {
		return email;
	}
	public void setTelephone(int telephone) {
		this.telephone = telephone;
	}
	public int getTelephone() {
		return telephone;
	}
}

Obtaining an OpenJPA datastore connection

After you've built the entity model, you need to implement connection logic to establish connectivity with your datastore (which could be any type of database). You could write a separate layer containing logic for connecting OpenJPA and the database. A simple approach is to have all database-related configurations in a properties file, and then define a class, such as OpenJpaAdminService, that abstracts the database connectivity. The logic of connecting to the database uses the getEntityManager() method. Whenever it is called from OpenJpaAdminService, you can call a lookup for the properties file so OpenJPA knows which database to connect to.

In the example provided in the download, OpenJpaMediator.java is the class that handles all the operations of OpenJPA. In the constructor of this class, the example calls the OpenJpaAdminService.getEntityManager() function to check for a properties file called dbConnection.properties. You can connect to a database by two means:

  • The typical mode, where you use JDBC driver details to connect.
  • Use JNDI look-up to get a JDBC connection (refer to OpenJpaAdminService.java in the download file).

REST resource modeling

Apache Wink is a framework for the simple implementation and consumption of REST web services, which are resources identified by unique URIs. Each resource has one or more representations that are transferred between the client and the service during a web service invocation. Wink provides:

  • The necessary infrastructure for defining and implementing the resources in a RESTful architectural style, which in turn facilitates uniform interface, multiple representations, and services introspection.
  • API feature support for REST web services. Wink is a Java-based API, and it uses annotations to simplify development and deployment of web service clients and end points.

Though it is possible to implement RESTful services using servlets, there is always too much HTTP code required to implement the business logic. Wink hides all the HTTP code and binds the servlets nicely to individual methods in the Java classes.


Representing a resource class

A resource represents a serviceable component that enables the retrieval and manipulation of data. A resource class defines resource methods that help implement the business logic. Listing 3 shows how to create a resource class for the Employee resource.

An end user always represents a resource in terms of XML or JSON. When the user needs to create or update a new instance of the resource, they pass the corresponding XML or JSON of that resource. Wink annotations in the resource class actually marshall the XML or JSON into a Java object. The advantage of defining an instance of an entity object (_Employee) is that at the end of marshalling of XML or JSON, you have an entity object ready to be persisted into the datastore. Thus, you can use the features of the Wink framework to persist an OpenJPA entity object. Similarly, when a user wants to retrieve any instance of the resource, OpenJPA retrieves the resource from the datastore and provides the entity object. Wink annotation helps in unmarshalling the retrieved entity object into XML or JSON and sending it to the end user.

Listing 3. Resource representation
package rest.resource;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import openJpa.model._Employee;

/**
 * @XmlAccessorType Controls whether fields or Javabean properties are 
 * serialized by default
 * XmlAccessType.PROPERTY: Every getter/setter pair in a JAXB-bound class will
 * be automatically bound to XML, unless annotated by XmlTransient. Fields are 
 * bound to XML only when they are explicitly annotated by some of the JAXB 
 * annotations.
 *
 */
 
@XmlAccessorType(XmlAccessType.PROPERTY)
/**
 * @XmlRootElement: Maps a class to an XML element
 */
 
@XmlRootElement(name="employee")
public class Employee {
/**
 * Instantiate Enity Object of Employee to achieve integration of APACHE WINK 
 * and OPEN JPA	
 */
private _Employee modelEmployee;
	
	public Employee() {
		super();
		this.modelEmployee = new _Employee();
	}
	
	public Employee(_Employee modelEmployee) {
		this.modelEmployee = modelEmployee;
	}
	
	@XmlTransient
	public _Employee getEmployee() {
		return this.modelEmployee;
	}
	public void setEmployee(_Employee modelEmployee)
	{
		this.modelEmployee = modelEmployee;
	}
	/**
	@XmlElement: Maps a JavaBean property to a XML element derived from property name
	*/
	@XmlElement(name = "employeeName")
	public String getEmployeeName() {
		return modelEmployee.getEmployeeName();
	}
	
	public void setEmployeeName(String employeeName) {
		modelEmployee.setEmployeeName(employeeName);
		
	}
	
	@XmlElement(name = "address")
	public String getAddress() {
		return modelEmployee.getAddress();
	}
	
	public void setAddress(String address) {
		modelEmployee.setAddress(address);
	}
	
	@XmlElement(name = "email")
	public String getEmail() {
		return modelEmployee.getEmail();
	}
	
	public void setEmail(String email) {
		modelEmployee.setEmail(email);
	}
	
	@XmlElement(name = "telephone")
	public int getTelephone() {
		return modelEmployee.getTelephone();
	}
	
	public void setTelephone(int telephone) {
		modelEmployee.setTelephone(telephone);
	}
	
	@XmlElement(name = "employeeId")
	public int getEmployeeId() {
		return modelEmployee.getEmployeeId();
	}
	
	public void setEmployeeId(int employeeId) {
		modelEmployee.setEmployeeId(employeeId);
	}
	
	@XmlElement(name = "version")
	public int getVersion() {
		return modelEmployee.getVersion();
	}
	
	public void setVersion(int version) {
		modelEmployee.setVersion(version);
	}
}

CRUD operations

This section covers the basic CRUD operations that can be performed on the Employee resource using the Wink framework and OpenJPA. For each operation, there will be a unique URI defined and an HTTP method. For the create and update operations, resource data (Employee details) must be represented as Content-Body. Content-Body for the Employee resource can be in either JSON or XML. Apache Wink supports XML, JSON, HTML, and Atom. Table 1 shows the design of the CRUD operations.

Table 1. CRUD operations
OperationDescriptionResource/URIResource data
CREATEIncludes facility for users to create a new resource. In the example, this operation includes creating a new Employee or adding a new Employee to an existing Database.

HTTP method: POST
/employeeContent-Body will include details of Employee in a specific representation. Every RESTful interface can decide on the different kinds of representations it supports for its clients. For example, the XML structure in Listing 1 can be Content-Body to create a new Employee.
RETRIEVEAllows a user to retrieve details of an existing employee through Employee Id. The data retrieved could be represented in different representations that REST supports for clients. For example, /employee/121: retrieves details of the employee whose ID is 121.

HTTP method: GET
/employee/{id}Content-Body will not be present for GET calls. GET should be a safe, read-only idempotent call and should not alter the state of the resource in any manner.
UPDATEIncludes a facility for users to update an existing resource. In the example, this operation includes updating an existing Employee in the database.

HTTP method: PUT
/employeeContent-Body will include details of Employee in a specific representation. Every RESTful interface can decide on the different kinds of representations it supports for its clients. For example, the XML structure in Listing 1 can be Content-Body to update an Employee.
DELETEAllows a user to delete details of an existing employee through Employee Id. After deletion, the user will get the HTTP response as to whether the employee is successfully deleted or not. For example, /employee/121: deletes details of the employee whose ID is 121.

HTTP method: DELETE
/employee/{id}Content-Body will not be present for DELETE calls.

Sample action class

An action class defines the implementation of all HTTP CRUD operations that can be implemented for a resource. Apache Wink receives HTTP requests and dispatches a wrapped HTTP request to the appropriate method written in the action class. Each HTTP request should map to a method in the action class based on the HTTP request parameters, the resource method definitions, and the MIME type.

Listing 4 shows how to create an action class for the Employee resource. In the example, you create an EmployeeAction class to implement the Apache Wink RESTful service. It consists of four methods—one for each CRUD operation.

Listing 4. Employee action class implementation
package rest.action;

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 javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import openJpa.mediator.EmployeeOpenJpaMediator;
import openJpa.model._Employee;
import rest.resource.Employee;

@Path(value = "/employee")
public class EmployeeAction {
	
	/**
	 * @param employee
	 * CREATE: @return This method is used to create new Employee
	 */
	@POST
	@Consumes(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	@Produces(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Response persistEmployee(Employee employee) {
		EmployeeOpenJpaMediator dao = new EmployeeOpenJpaMediator();
		_Employee _employee = employee.getEmployee();
		try {
			dao.beginTransaction();
			dao.persist(_employee);
			dao.commitTransaction();

		}  catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			dao.rollbackTransaction();
			return Response.status(400).entity(
					"Employee create failed!").build();
		} finally {
			dao.close();
		}
		Employee employeeCreated = new Employee(_employee);
		return Response.ok(employeeCreated).build();
	}
	
	/**
	 * @param id
	 * RETRIEVE: @return This method is used to retrieve a particular Employee 
	   through employeeId
	 */
	@GET
	@Path("/{id}")
	@Produces(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
	public Response findEmployee(@PathParam(value = "id") int id) {

		EmployeeOpenJpaMediator employeeDao = new EmployeeOpenJpaMediator();
		_Employee u = new _Employee();
		try {
		if ((u = (_Employee) employeeDao.getById(_Employee.class, id)) != null) {
			return Response.ok(new Employee(u)).build();
		} else {
			return Response.status(404).entity(
			"Employee id does not exist").build();
		}
		}catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return Response.status(404).entity(
					"Employee id does not exist").build();
		}
	}
	
	/**
	 * @param employee
	 * UPDATE: @return this method is used to update a particular Employee 
	   already existing
	 */
	@PUT
	@Produces(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	@Consumes(value = { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
	public Response updateEmployee(Employee employee) {
		EmployeeOpenJpaMediator ud = new EmployeeOpenJpaMediator();
		_Employee _employee = employee.getEmployee();
		try {
			ud.beginTransaction();
			ud.update(_employee);
			ud.commitTransaction();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			ud.rollbackTransaction();
			return Response.status(409).entity(
					"Employee update failed!").build();

		} finally {
			ud.close();
		}

		Employee employeeUpdated = new Employee(_employee);
		return Response.ok(employeeUpdated).build();
	}
	
	/**
	 * @param id
	 * DELETE: This method is used to delete a particular Employee through employeeId
	 */
	@DELETE
	@Path("/{id}")
	public Response deleteEmployee(@PathParam(value = "id") int id) {
		EmployeeOpenJpaMediator pd = new EmployeeOpenJpaMediator();
		_Employee _employee = (_Employee) pd.getById(_Employee.class, id);
		if(_employee!=null){
		try {
			pd.beginTransaction();
			pd.delete(_employee);
			pd.commitTransaction();

		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			pd.rollbackTransaction();
			return Response.status(400).entity(
					"Employee delete had an error!").build();
		} finally {
			pd.close();
		}
	return Response.ok().build();
		}
		else{
			return Response.status(400).entity(
			"Employee ID does not exist!").build();
		}
	}
}

Action class invoker

Whenever a REST servlet is initialized, the RestApp class, which actually extends the Application class, is invoked. RestApp helps Apache Wink get the corresponding action class and perform corresponding HTTP operations as coded in the action class. Thus, the action class is registered with the framework. Listing 5 shows how to create an action class invoker for the EmployeeAction class.

Listing 5. Employee action class implementation, continued
 package rest.app;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;
import rest.action.EmployeeAction;

public class RestApp extends Application {
	@Override
	public Set<Class<?>>: getClasses() {
		Set<Class<?>> classes = new HashSet<Class<?>>();
		addResources(classes);
		return classes;
	}
	
	public Set<Class<?>> addResources(Set<Class<?>>classes)
	{
		classes.add(EmployeeAction.class);
		return classes;
	}
	
}

Summary

In this article, you have learned how the REST architecture, OpenJPA implementation, and the Apache Wink standard can help to simplify RESTful service implementations. The integration of OpenJPA and the new Apache Wink framework can help you implement HTTP operations on resources through a REST service. You explored OpenJPA entity modeling, resource modeling, URI design, and using Wink annotations to implement CRUD operations on a sample resource.


Download

DescriptionNameSize
Code for REST resources modeled using OpenJPAOpenJPA.zip9KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=775752
ArticleTitle=Build REST resources using Apache Wink and OpenJPA
publish-date=11292011