Friday, December 08, 2006

Part II: Creating a Simple Persistence Layer for an EJB3 Application


Follows [Part I] ...

The Entertain(r) application stores (or persists) data in a database. For now, the only data we need to store is about movies, including the title, the MPAA rating, the DVD number in my library, the date added to the library, the genre, and a short synopsis. The movie data will be represented in a Movie class, which will be annotated to become the entity.
Tools: NetBeans 5.5, Sun Java System Application Server 9, MySQL 5.

Create the Persistence Unit
Persistence units describe the datasource to the application.
- Right-click the ejb module > New > File/Folder | Persistence > Persistence Unit > [Next]. Datasource=jdbc/entertain. [Finish]. A persistence.xml descriptor file is created.

Create the Entity
An entity is a representation of an object in the datasource. Since we plan to persist movies, it's only appropriate that we call the movie entity Movie. Entities are POJOs that are annotated to indicate that they should be persisted into the database.
- Right-click the ejb module > New > File/Folder | Persistence > Entity Class > [Next]. Class Name = Movies; Package = movie.ejb. [Finish]. An entity class is created and opened in the IDE. It already has the @Entity annotation, along with @Id/@GeneratedValue (auto-generated primary key), is serializable, overrides equals(), toString(), and hashCode() methods - all requirements for an entity class.
- Add the entity's fields:
String title;
String genre;
String rating;
String synopsis;
Date dateAdded;
int dvdNumber;
- Generate bean-style getters and setters for the fields: right-click in the source file > Refactor > Encapsulate Fields ...
- Add the @Temporal(value = TemporalType.DATE) annotation for the dateAdded field. This is so that the persistence provide can translate dates correctly to the TIMESTAMP data type used in most databases.

Create the Session Bean
The session bean provides a facade that can be used to perform CRUD operations.
- Right-click the ejb module > New > File/Folder | Persistence > Session Beans for Entity Classes > [Next]. From the available list, select 'Movie (movies.ejb)' and click [Add] then [Next], then [Finish]. A stateless session bean is created and includes methods to create, edit, destroy, find, and find all movies.
** Fix:: Change the destroy() method to ensure that we operate on a managed object:
public void destroy(Movie movie) {
Movie managed = em.merge(movie);
em.remove(managed);
}

Create the Servlet
We'll use a servlet to test the persistence layer (model, par MVC), which includes the data source, persistence unit, entity class, and session bean - so far all defined in the context of the EJB module. The servlet shall exist in the web module, however.
- Right-click the war module > New > File/Folder | Web > Servlet > [Next]. Class Name = MovieServlet; Package = movie.servlet; [Finish]. A servlet class is created an opened in the IDE.
- Inject the session bean resource: right-click in the source > Enterprise Resources > Call Enterprise Bean. Select MovieFacade, click [OK]. This create an @EJB annotated reference to the session bean.
- Enter some useful code in the processRequest() method (to which all POST and GET requests are redirected). In this application, we will enter decision logic for the CRUD operations we need to test. To add, edit, remove, and find a movie, call the movieFacade methods. [Full servlet code]
- Remember to change the servlet's URL pattern to something simpler, like /Movie
- The application should be deployable now, accessible at something like http://localhost:8080/Entertain-war/.

Results:
The servlet is nowhere near perfect (for example, it does not check data lengths before posting to database fields - defaults are 255 characters), and has a lot of hard-coded lines. But it serves the simple purpose of testing the persistence layer, now composed of the data source, persistence unit, entity class, and session bean. If you are into MVC development, that layer is the model part, and the servlet serves as both the controller and view.