4. Step 3 - Configure the App

In this section we show how to

  1. configure an app to connect with a database in a controller class,

  2. obtain the EntityManager and UserTransaction instances required for performing database operations,

  3. wrap an app in a WAR file and deploy it to a web server for execution.

4.1. Create the EntityManager and UserTransaction objects

A controller class contains the code that glues the views to the model, as well as all methods that do neither belong to the model nor to the view, like getting a connection with the database server. In our example app, this class is pl.c.BookController in the src/pl/c folder.

JPA requires an EntityManager object for executing JPQL queries (with SELECT) and data manipulation statements (with INSERT, UPDATE and DELETE). Also, in order to perform database write operations, a UserTransaction object is required for starting and completing transactions. In a standalone application, the programmer has to create an entity manager and a transaction manually, using a factory pattern as shown in the following code fragment:

EntityManagerFactory emf = 
EntityManager em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();

A JPA-enabled Java web application normally runs in an environment called "container" (in our case this is TomEE), which takes care of creating an EntityManager and a UserTransaction object if the right annotations are used. The code responsible for this is part of the controller class ( e.g., pl.c.BookController) since the controller is responsible for managing the database connections.

public class BookController {
  @PersistenceContext( unitName="MinimalApp")
  private EntityManager em;
  @Resource() UserTransaction ut;

  public List<Book> getBooks() {...}
  public void refreshObject( Book book) {...}
  public String create( String isbn, String title, 
      int year) {...}
  public String update( String isbn, 
      String title, int year) {...}
  public String delete( String isbn) {...}

A closer look at this code shows that it is sufficient to use the @PersistenceContext annotation and provide a unitName (see the next section) for obtaining an EntityManager instance at runtime. Also, obtaining a UserTransaction instance at runtime is as simple as using the @Resource annotation for the user transaction reference property ut. Not only that the required code is short and simple, but if the database type is changed (e.g. when we switch from MySQL to an Oracle database), this code remains the same.

4.2. Configure the JPA database connection

In the previous section, discussing the BookController class, we have shown how to obtain the EntityManager and UserTransaction objects required for performing database operations. The @PersistenceContext annotation of the EntityManager reference property requires a unitName, which is just a name used for identifying the storage management configuration defined in the src/META-INF/persistence.xml file. In our example app this file has the following content:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" 
 <persistence-unit name="MinimalApp">
   <!-- Request auto-generation of the database schema -->
   <!-- Use the JPA annotations to create the database schema -->

The configuration name ("MinimalApp") is defined by the name attribute of the persistence-unit element. This is the value we have to use for the unitName property of the @PersistenceContext annotation.

The persistence-unit element has three content parts:

  1. One or more class elements, each one containing the fully qualified name of an entity class of the app (like pl.m.Book in our example app).

  2. A set of configuration property elements used for providing further configuration settings.

  3. A jta-data-source element for specifying the configuration block in the config/TomEE.xml web server configuration file in the web server installation folder.

In our persistence.xml file, two configuration properties have been set:

  • javax.persistence.schema-generation.database.action, with the possible values: none (default), create, drop-and-create and drop. It specifies if the database schema is to be automatically created and additionally allows to drop the existing tables before creating the new ones (with drop or drop-and-create). .

  • javax.persistence.schema-generation.create-source, with the possible values metadata (default), script, metadata-then-script and script-then-metadata. It specifies the source of information used to create the database schema. The value metadata enforces using the JPA annotations while the value script allows using an external script for defining the schema.

The jta-data-source element of our persistence.xml file refers to the Resource element with id value "MinimalApp" in the config/TomEE.xml file, which has the following content:

<?xml version="1.0" encoding="UTF-8"?>
  <Resource id="MinimalApp" type="DataSource"> 
    JdbcDriver com.mysql.jdbc.Driver 
    JdbcUrl jdbc:mysql://localhost:3306/MinimalApp
    UserName MinimalApp 
    Password MinimalApp 
    JtaManaged true 

The Resource element contains the information required to connect with the database (user name, password, access URL and the Java class name of the connection driver). Notice that in order to use a connection driver, one needs to download the jar file for that specific technology and copy it into the lib subfolder of the TomEE installation folder. Finally, TomEE needs to be restarted in order to load the new driver. See also our instructions page, for additional details related to JDBC drivers, and in particular how to use the official MySQL JDBC driver "Connector/J".

4.3. Create the main template

The main template, called page.xhtml, is shown below. It has two sub-templates:

  1. header.xhtml defines the general header information items (such as the application name)

  2. footer.xhtml defines the general footer information items (such as a copyrights notice)

Both sub-templates are included in the main template with the help of a ui:include element. We add all three template files to the WebContent/WEB-INF/templates folder.

The content of our HTML5-compliant main template page.xhtml is the following:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
  <meta charset="UTF-8" />
  <title>Public Library</title>
   <ui:insert name="headerTitle"/>
   <ui:insert name="headerMenu">
    <ui:include src="/WEB-INF/templates/header.xhtml"/>
   <ui:insert name="main"/>
   <ui:insert name="footer">
    <ui:include src="/WEB-INF/templates/footer.xhtml"/>

In the code, one can see that some HTML elements are used (e.g., title, header, main and footer) while others like h:head and ui:insert are not HTML elements, but have been defined by JSF. For instance, JSF defines its own head element h:head for injecting special HTML code such as script elements that load JavaScript code for HTTP messaging between the web browser and the back-end Java program by invoking methods of the JavaScript API XML HTTP Request (XHR) .

Our main template defines three content regions: header, main and footer. The header and footer regions are defined by sub-templates included with the help of the ui:include element.

The header.xhtml sub-template contains the application menu, corresponding to the CRUD operations:

<nav xmlns:h="http://java.sun.com/jsf/html"> 
    <li><h:link outcome="create">C</h:link></li>
    <li><h:link outcome="retrieveAndListAll">R</h:link></li>
    <li><h:link outcome="update">U</h:link></li>
    <li><h:link outcome="delete">D</h:link></li>

The footer.xhtml sub-template contains the "Back to main menu" link, which we like to show on each application page, except the index page:

<h:link outcome="index" xmlns:h="http://java.sun.com/jsf/html">
  Back to main menu

Notice that the h namespace must be defined once again in footer.xhtml even if it has already been defined in page.xhtml. In the footer template component, we define the "Back to main menu" operation, which is going to be injected into each page that uses this template. The main region is dynamic, and will be replaced with the content generated by a facelet template.

JSF is using the following namespaces:

  • xmlns:ui="http://java.sun.com/jsf/facelets" for the JSF Facelets Tag Library providing templating elements (like ui:insert for specifying the region of a template where to inject the facelet content).

  • xmlns:h="http://java.sun.com/jsf/html" for the JSF HTML Tag Library providing JSF versions of HTML elements, which are then mapped to HTML elements. For example h:inputText, which is mapped to an HTML input element.

  • xmlns:f="http://java.sun.com/jsf/core" for the JSF Core Tag Library providing custom actions or elements that are independent of any particular render kit. For example, f:actionListener can be used to define a Java method which is executed when the user clicks a button.

  • xmlns:p="http://xmlns.jcp.org/jsf/passthrough" for using HTML attributes in JSF HTML elements and passing them through to the generated HTML. For example, with p:type in, <h:inputText p:type="number"> an HTML5 input type attribute can be created in the generated HTML: <input type="number">.

  • xmlns:c="http://java.sun.com/jsp/jstl/core" for the JSTL Core Tag Library providing all kinds of features, like dealing with loops and defining variables. For example, we can use <c:set var="isbn" value="#{book.isbn}"/> to create a variable named isbn which can then be used in the view code for conditional expressions.

  • xmlns:fn="http://java.sun.com/jsp/jstl/functions" for the JSTL Functions Tag Library providing various utility functions, such as string converters. For example, we can use fn:toUpperCase to convert a string to its uppercase representation.

4.4. Define the managed beans needed in facelets

JavaBean classes, including entity classes, can be used for creating 'managed beans' with the help of the @ManagedBean annotation, which allows defining the name of a variable for accessing the created bean in the view code, typically in an EL expression. In our example app, we want to access a Book bean as well as a BookController bean, therefore both classes have to be annotated as follows:

@Entity @Table( name="books")
@RequestScoped @ManagedBean( name="book")
public class Book { ... }

@SessionScoped @ManagedBean( name="bookCtrl")
public class BookController { ... }

Notice how a lifetime scope can be specified for a managed bean with a scope annotation. In our example the book bean is @RequestScoped, this means the instance exists as long as the HTTP request and the associated response are being processed. The bookCtrl bean is @SessionScoped, which means it is created when the session starts, and destroyed when the session is closed. Other scopes are available, but in our example we only need these two.

4.5. Build the WAR file and deploy it to TomEE

There are multiple ways in which we could compile the source code, create the war file and deploy it to a TomEE server. For example one can use Eclipse IDE or Netbeans, or one can use ANT and create a script that takes care of all these tasks.

We provide an ANT script that allows automatically creating the structure of a Java web application, compile the Java source code, build the WAR file and deploy it to a TomEE web server. Our ANT script generates an Eclipse IDE compatible folder structure, so in case you want to use Eclipse, simply create a project from the existing application code. The ANT installation instructions, detailed description of the available tasks as well as download links are available on our instructions page.

For our "PublicLibrary" example application, we have used the ANT script and the following steps were needed:

  • create the application folder structure: ant create app -Dappname=publicLibrary -Dpkgname=pl.

  • compile the Java code and build the war file: ant war -Dappname=publicLibrary.

  • deploy the application to TomEE server: ant deploy -Dappname=publicLibrary. This operation also builds the war file, if it was not already created using the war task, as shown before.

Hint: we do not recommend using spaces in folder names, but if for any reason, the application name needs to contain spaces, then it has to be enclosed in double quotes, e.g. create app -Dpgkname=hw -Dappname="Hellow World". In this case it was required to provide the pkgname parameter, while "Hello World" is not a valid Java identifier, since it contains a white space.