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.