In my previous post we setup a Maven/Eclipse project for developing RESTful web applications on JBoss AS 7. A RESTful web service that is not using a database is some what of an oddity. Therefor in this blog we'll extend the project with JPA.
Configuration: Adding a JBoss Module
I want to use Postgres as the underlying database. To install the required JDBC driver for Postgres in the JBoss AS 7 container, we need to add a module. As I mentioned in the previous post, the module structure of JBoss is reflected on the file system.

The files in the ''main'' directory that constitute the module are the folloing:
- module.xml describes the module. The content follows below.
- postgresql-9.0-801.jdbc4.jar is the postgres JDBC4 driver.
- postgresql-9.0-801.jdbc4.jar.index is an index file generated by JBoss Annotation Indexer when the modules are scanned.
So in order to add a module to the JBoss container, we need to write an XML file: [xml title="module.xml"] <module xmlns="urn:jboss:module:1.0" name="org.postgres"> <resources> <resource-root path="postgresql-9.0-801.jdbc4.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module> [/xml] Now we also need to enlist the datasource in the standalone.xml: the main configuration for JBoss. You'll find it in the ''standalone/configuration'' subdirectory of the JBoss installation. The file already has a datasource and driver for h2. So we add a new node: [xml title="standalone.xml" highlight="9,10-13"] <?xml version='1.0' encoding='UTF-8'?> <server name="brandhout.local" xmlns="urn:jboss:domain:1.0"> ... <datasources> <datasource> ... </datasource> <drivers> <driver name="postgres" module="org.postgres"> <xa-datasource-class> org.postgresql.xa.PGXADataSource </xa-datasource-class> </driver> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class> org.h2.jdbcx.JdbcDataSource </xa-datasource-class> </driver> </drivers> </datasources> ... </server> [/xml] Now, after restarting the server, we can finish the configuration using the admin console.

The ''New Datasource'' button will open up a dialog that will guide you through a few simple steps to configure the datasource. The changes will be persisted in the standalone.xml, which will now contain a fragment like this: [xml title="standalone.xml"] .. <datasource jndi-name="LibraryDS" pool-name="LibraryDS_Pool" enabled="true" jta="true" use-java-context="true" use-ccm="true"> <connection-url> jdbc:postgresql://localhost:5432/library </connection-url> <driver> postgres </driver> <security> <user-name> library </user-name> <password> library </password> </security> </datasource> ... [/xml]
Reading from the database
Now we need to configure our application to read from the database. To configure the database as a persistence context in JPA, we add a persistence.xml to our project. [xml language="src/main/resources/persistene"] <?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns="https://java.sun.com/xml/ns/persistence"; xmlns_xsi="https://www.w3.org/2001/XMLSchema-instance"; xsi_schemaLocation="https://java.sun.com/xml/ns/persistence https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"; version="1.0"> <persistence-unit name="library" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/LibraryDS</jta-data-source> <properties> <property name="hibernate.hbm2ddl.auto" value="create-drop" /> </properties> </persistence-unit> </persistence> [/xml] The java code we have to write is quite trivial JPA code mixed in with some JAX-RS annotation. For completeness they are included here below (collapsed). [java title="com/xebia/library/model/Book.java" collapse="true"] package com.xebia.library.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.SequenceGenerator; import javax.ws.rs.FormParam; @Entity @SequenceGenerator(name="BOOK_SEQ", sequenceName="BOOK_SEQ") public class Book { @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="BOOK_SEQ") @FormParam("id") private Long id; @FormParam("title") private String title; public Long getId() { return id; } public String getTitle() { return title; } } [/java] [java title="com/xebia/library/BookRepository.java" collapse="true"] package com.xebia.library; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import java.util.List; import javax.ejb.Local; 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 org.jboss.resteasy.annotations.Form; import com.xebia.library.model.Book; @Local @Path("books") @Produces(APPLICATION_JSON) public interface BookRepository { @GET @Path("/") List<Book> all(); @POST @Path("/") Book create(@Form Book entity); @GET @Path("/{id}/") Book getById(@PathParam("id") long id); @PUT @Path("/{id}/") Book update(@Form Book entity); @DELETE @Path("/{id}/") void remove(@PathParam("id") long id); } [/java] [java title="com/xebia/library/impl/BookRepositoryBean.java" collapse="true"] package com.xebia.library.impl; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import com.xebia.library.BookRepository; import com.xebia.library.model.Book; @Stateless public class BookRepositoryBean implements BookRepository { @PersistenceContext private EntityManager em; @Override public List<Book> all() { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Book> query = builder.createQuery(Book.class); Root<Book> root = query.from(Book.class); query.orderBy(builder.asc(root.get("id"))); return em.createQuery(query).getResultList(); } @Override public Book create(Book book) { em.persist(book); return book; } @Override public Book byId(long id) { return em.find(Book.class, id); } @Override public Book update(long id, Book book) { return em.merge(book); } @Override public void delete(long id) { em.remove(byId(id)); } } [/java] A few things to notice:
- The JPA entity is also used as a ''backing'' object for Form posts. The @FormParam annotation is used to parameters posted to the fields of the object.
- The Repository is now also used as a local interface for the stateless bean.
After deploying the application to the server, we can test it using this simple tool.

Conclusion
With just a few classes we were able to deploy a RESTful web service that enables users to maintain a (rudimentary) book list. The WAR that we build is really tiny: It only contains a few classes. The application relies on JEE specifications that are implemented in the JBoss container. A few remarks about this:
- Developing a JEE application becomes much simpler and more fun! It feels almost like RAD web development alla Grails.
- Testing an application like this is non-trivial: Much of the functionality is provided by the container. With a 'thicker' maven project with Hibernate and Spring/Seam as dependencies, we could mimic (parts of) the deployed application in an in-build testing environment. How do we do this now? One possible answer is to use Arquillian. A future blog will have to cover that...
Of course the application we have now is far from finished. To start with, it has no user interface...
Maarten Winkels
Contact