My name is Gurkan Erdogdu and I am the CTO of the MechSoft Mechanical and Software Solutions. I have been active in the Java and Java EE platform more than 10 years. Strong supporter for the Free and Open Source Software, and actively participating within the Open Source based foundations like, Apache Software Foundation, JBoss, and recently Open Web Foundation. I am the member of the Apache Software Foundation and Open Web Foundation. Writing blog at gurkanerdogdu@blogspot.com. Gurkan has posted 24 posts at DZone. View Full User Profile

Using Defne Framework with RESTful Web Services via Apache Wink

08.01.2010
| 7086 views |
  • submit to reddit

Defne is a service oriented web application framework. The main motivation behind Defne is ease of use. Defne allows developers to concentrate on their business logic while it provides all other application requirements such as transaction and security. With Defne, you can implement Java EE based business logics easily.

Apache Wink  is a complete Java based solution for implementing and consuming REST based Web Services. The goal of the Wink framework is to provide a reusable and extendable set of classes and interfaces that will serve as a foundation on which a developer can efficiently construct applications. Apache Wink 1.1 aims to be a fully compliant implementation of the JAX-RS v1.1 specification.

 In this article, we are going to see how one implements a web application using Wink and Defne together. While Wink provides RESTful web services, Defne provides implementation of the business services with service oriented fashion.

Requirements

In this article we use SIwpas, http://code.google.com/p/siwpas, Simple Web Profile Application Server that contains all necessary libraries. If you wish to use Tomcat, Jetty or any other application server, you have to bundle necessary libraries with your application or server classpath.

 Defne libraries could be downloaded from  http://code.google.com/p/defne/. Apache Wink libraries could be downloaded from http://incubator.apache.org/wink/.

Sample Web Application

In this article, our application is a simple web application that 

  • Creates a book instance with "name and author" and returning "identity" of the created book : We will  POST  form parameters "name" and "author" to create a book instance.
  • Gets a book info from given "book identity" : We will get book information using GET request, such as; http://localhost:8080/rest-example/books/{book_id}


RESTful Web Service

We first write RESTful Web Service

@Path("/books")
public class BookResource
{
@POST
@Consumes(value=MediaType.APPLICATION_FORM_URLENCODED)
@Produces(value=MediaType.TEXT_PLAIN)
public String createBook(MultivaluedMap<String, String> formParams)
{
Message message = MessageFactory.newMessage(IBookService.SERVICE_NAME, IBookService.ADD_OPERATION.OPERATION_NAME);
message.putMessageParameter(IBookService.ADD_OPERATION.INPUT.NAME, formParams.getFirst(IBookService.ADD_OPERATION.INPUT.NAME));
message.putMessageParameter(IBookService.ADD_OPERATION.INPUT.AUTHOR, formParams.getFirst(IBookService.ADD_OPERATION.INPUT.AUTHOR));

message = PojoServiceExecutor.execute(message);

return message.getMessageParameter(String.class, IBookService.ADD_OPERATION.OUTPUT.ID);
}

@GET
@Path(value="{bookid}")
public String showBookInfo(@PathParam(value="bookid") String id)
{
Message message = MessageFactory.newMessage(IBookService.SERVICE_NAME, IBookService.GET_INFO_OPERATION.OPERATION_NAME);
message.putMessageParameter(IBookService.GET_INFO_OPERATION.INPUT.ID, id);

message = PojoServiceExecutor.execute(message);

return message.getMessageParameter(Book.class, IBookService.GET_INFO_OPERATION.OUTPUT.BOOK).toString();
}
}

Here, you see RESTful root resource, BookResource that contains one sub-resource.

From Wink User Guide

Resources are one of the fundamental concepts in REST. REST emphasizes the manipulation of resources rather than issuing function calls. Resources have unique identifiers. In HTTP terms, this means associating every resource with at least one URL.

In order to manipulate a resource, requests are made with a specific HTTP method. For instance, in order to retrieve a representation of a resource, an HTTP GET request to the resource's URL is issued. In order to create a new item in a collection, an HTTP POST can be used with the collection URL. Application developers define resources and the HTTP methods in order to quickly manipulate them by using regular plain old Java objects and JAX-RS annotations.

Let's return our case, we have one Root Resource, BookResource, for handling " http://localhost:8080/rest-sample/rest/books" URL and one sub-resource for handling  "http://localhost:8080/rest-sample/rest/books/{book_id}" URL.

  • One is accessed using http://localhost:8080/rest-sample/rest/books. When the application form is submitted, "createBook" method is called by the Apache Wink runtime. It creates Defne message and call ADD_OPERATION of the Book Service.
  • One is accessed using http://localhost:8080/rest-sample/rest/books/{book_id}.  When you hit the url with the book_id, "showBookInfo" method is called by the Apache Winkruntime. It creates Defne message and call GET_INFO_OPERATION of the Book Service.

Defne Book Service

Here is the Defne Book Service interface and implementation.

Service interface,

public interface IBookService
{
String SERVICE_NAME = "BookService";

interface ADD_OPERATION{

String OPERATION_NAME = "createBook";
interface INPUT{
String NAME = "NAME";
String AUTHOR = "AUTHOR";
}

interface OUTPUT{
String ID = "ID";
}

}

interface GET_INFO_OPERATION{
String OPERATION_NAME = "getBookInfo";
interface INPUT{
String ID = "ID";
}

interface OUTPUT{
String BOOK = "BOOK";
}

}
}

 And here is the implementation. Its very easy to write Defne services,

@Service(name="BookService")
public class BookServiceImpl
{

@Operation
@TransactionAttribute(TransactionPolicy.WITH_TRANSACTION)
@EntityManagerAttribute
public static Message createBook(Message message) throws DefneException
{
String name = message.getMessageParameter(String.class, IBookService.ADD_OPERATION.INPUT.NAME);
String author = message.getMessageParameter(String.class, IBookService.ADD_OPERATION.INPUT.AUTHOR);

Book book = new Book();
book.setName(name);
book.setAuthor(author);

EntityManager manager = EntityManagerUtil.getEntityManagerFromBag(message);
manager.persist(book);

Message oMessage = MessageFactory.newMessage();
oMessage.putMessageParameter(IBookService.ADD_OPERATION.OUTPUT.ID,Integer.toString(book.getId()));

return oMessage;
}

@Operation
@TransactionAttribute(TransactionPolicy.NO_TRANSACTION)
@EntityManagerAttribute
public static Message getBookInfo(Message message) throws DefneException
{
EntityManager manager = EntityManagerUtil.getEntityManagerFromBag(message);
Query query = manager.createQuery("select c from Book c where c.id=:id");
query.setParameter("id", Integer.parseInt(message.getMessageParameter(String.class, IBookService.GET_INFO_OPERATION.INPUT.ID)));

Book book = (Book) query.getSingleResult();
Message oMessage = MessageFactory.newMessage();
oMessage.putMessageParameter(IBookService.GET_INFO_OPERATION.OUTPUT.BOOK,book);

return oMessage;
}

}

TransactionAttribute and EntityManagerAttribute annotations are used for defining Transaction and JPA requirements of the service operation.

 In the first operation, we get form parameters (name and author) and create Book instance. In the second operation, we get "id" of the book instance that we query for the book info.

Wink Application Class 

To register our RESTful service with Wink, we have to write application class that extends javax.ws.rs.core.Application.

public class WinkBookApplication extends Application
{

@Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(BookResource.class);

return classes;
}

}

Our HTML Page

This is the our simple HTML page for posting form parameters that provide Book information.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>REST Example</title>
</head>
<body>

<form action="/rest-sample/rest/books/" method="post">
<label>Name : </label>
<input type="text" name="NAME"/>

<br/>
<label>Author : </label>
<input type="text" name="AUTHOR"/>

<br/>

<input type="submit" value="Add Book"/>

</form>
</body>
</html>

When the form is posted, Wink finds related RESTful service from URL and call related method, BookResource#createBook, with MultivaluedMap<String, String> instance that contains form parameters.

When you hit the URL like, http://localhost:8080/rest-sample/rest/books/2,  Wink finds related RESTful service from URL and call related method, BookResource#showBookInfo with @PathParam(value="bookid") String instance that contains "2".

Configuration of the Wink

To use Wink, we have to add some configuration into "web.xml". Here is the complete web.xml file.

<web-app id="WebApp_ID" version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<display-name>Rest Example Application</display-name>

<listener>
<listener-class>org.defne.service.scanner.ScannerListener</listener-class>
</listener>

<servlet>
<servlet-name>Books</servlet-name>
<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.defne.server.rest.WinkBookApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Books</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>

 Here we register our Application instance with init-param. We also provide REST servlet URL handling, /rest/*. Listener is used for scanning Defne services.

beans.xml and defne-service.xml Files

Those files are used by the Apache OpenWebBeans and Defne respectively. defne-service.xml file is a marker file that is put into META-INF/ folder of the application classpath.  Defne framework looks for this file to scan deployment. beans.xml is a CDI configuration file.

JPA persistence.xml File

Defne framework uses Java Persistence API for  handling database operations. Here is the persistence.xml file used by the application,

 <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">

<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>

<class>org.defne.server.rest.Book</class>

<properties>
<property name="openjpa.jdbc.DBDictionary" value="hsql" />
<property name="openjpa.ConnectionDriverName" value="org.hsqldb.jdbcDriver" />
<property name="openjpa.ConnectionURL" value="jdbc:hsqldb:mem:test" />
<property name="openjpa.ConnectionUserName" value="sa" />
<property name="openjpa.ConnectionPassword" value="" />
<property name="openjpa.Log" value="DefaultLevel=TRACE"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>

</persistence-unit>
</persistence>

 We use Apache OpenJPA, that runtime is provided with SIwpas. If you wish to use another persistence provider, you have to bundle its libraries with your application and update configuration accordingly.

Complete Application

You can get complete rest-example application from  Defne SVN, http://tiny.cc/zs9sx

Conclusion

Defne provides an easy way to write your business logic using Java EE technologies. Defne services could be called by different clients easily such as, Pure AJAX, Standalone Java, Java Servlet, JSF, RESTful Services etc. We will add more clients at the next release, such as JMS, TCP, Web Service etc.

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.

Defne URLs

Web Site : http://code.google.com/p/defne/

SVN Site : http://code.google.com/p/defne/source/browse/

Maven Snapshot : https://oss.sonatype.org/content/repositories/snapshots/org/defne/

Maven : http://repo1.maven.org/maven2/org/defne/

Defne Discussion : http://groups.google.com/group/defnedev

Apache Wink URLs

Web Site :  http://incubator.apache.org/wink/

SVN Site : http://svn.apache.org/repos/asf/incubator/wink/

Enjoy!

Gurkan Erdogdu

ASF Member,http://apache.org

PMC Chair, Apache OpenWebBeans

CTO, MechSoft Mechanical and Software Solutions, http://www.mechsoft.com.tr

 

 

Published at DZone with permission of its author, Gurkan Erdogdu.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)