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.
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.
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.
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).
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.
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);
}
}
|
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
| Operation | Description | Resource/URI | Resource data |
|---|---|---|---|
| CREATE | Includes 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 | /employee | Content-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. |
| RETRIEVE | Allows 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. |
| UPDATE | Includes 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 | /employee | Content-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. |
| DELETE | Allows 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. |
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();
}
}
}
|
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;
}
}
|
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.
| Description | Name | Size | Download method |
|---|---|---|---|
| Code for REST resources modeled using OpenJPA | OpenJPA.zip | 9KB | HTTP |
Information about download methods
Learn
-
Apache Wink: Explore the
various aspects of the Apache Wink project.
- Apache Wink Developer Guide: Get a rudimentary understanding of
the Wink framework and the building blocks that comprise it.
- "RESTful web services with Apache Wink, Part 2: Advanced topics in
Apache Wink REST development" (developerWorks, March 2010): Read
about advanced topics in Apache Wink 1.0 development.
-
Representational state transfer: Read more on Wikipedia to get
up-to-speed quickly on REST concepts.
-
developerWorks Web
development zone: Find articles covering various web-based
solutions. See the Web
development technical library for a wide range of technical
articles and tips, tutorials, standards, and IBM Redbooks.
-
developerWorks
podcasts: Listen to interesting interviews and discussions for
software developers.
-
developerWorks technical events and webcasts: Stay current with
developerWorks technical events and webcasts.
- developerWorks on
Twitter: Join today to follow developerWorks tweets.
- developerWorks
on-demand demos: Watch demos ranging from product installation and
setup for beginners to advanced functionality for experienced
developers.
Get products and technologies
-
Apache Wink: Get the source
code and binaries of the latest version of the framework, along with other
example projects.
- IBM product
evaluation versions: Download or explore
the online trials in the IBM SOA Sandbox and get your hands on
application development tools and middleware products from DB2, Lotus,
Rational, Tivoli, and WebSphere.
Discuss
- Create your developerWorks profile today and set up a watchlist. Get connected and stay connected with developerWorks community.
- Find other developerWorks members interested in web development.

Sathish 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 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.





