In this section we show how to
configure an app to connect with a database in a controller class,
obtain the EntityManager and
UserTransaction instances required for performing
database operations,
wrap an app in a WAR file and deploy it to a web server for execution.
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 =
Persistence.createEntityManagerFactory("MinimalApp");
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.
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" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <persistence-unit name="MinimalApp"> <class>pl.m.Book</class> <properties> <!-- Request auto-generation of the database schema --> <property name="javax.persistence.schema-generation.database.action" value="create"/> <!-- Use the JPA annotations to create the database schema --> <property name="javax.persistence.schema-generation.create-source" value="metadata"/> </properties> <jta-data-source>jdbc/MinimalApp</jta-data-source> </persistence-unit> </persistence>
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:
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).
A set of configuration property elements used
for providing further configuration settings.
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"?>
<TomEE>
<Resource id="MinimalApp" type="DataSource">
JdbcDriver com.mysql.jdbc.Driver
JdbcUrl jdbc:mysql://localhost:3306/MinimalApp
UserName MinimalApp
Password MinimalApp
JtaManaged true
</Resource>
</TomEE>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".
The main template, called page.xhtml, is
shown below. It has two sub-templates:
header.xhtml defines the general header
information items (such as the application name)
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"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<meta charset="UTF-8" />
<title>Public Library</title>
</h:head>
<body>
<header>
<ui:insert name="headerTitle"/>
<ui:insert name="headerMenu">
<ui:include src="/WEB-INF/templates/header.xhtml"/>
</ui:insert>
</header>
<main>
<ui:insert name="main"/>
</main>
<footer>
<ui:insert name="footer">
<ui:include src="/WEB-INF/templates/footer.xhtml"/>
</ui:insert>
</footer>
</body>
</html>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">
<ul>
<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>
</ul>
</nav>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 </h:link>
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.
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.
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.