Taking TOTD #120 forward, we’ll add the following features to our application:
- Add database access using Java Persistence API 2.0
- Show type-safe Criteria API from JPA 2.0
- Use Context & Dependency Injection for JSF managed beans
- Add Ajax effects from Java Server Faces 2.0
- Add Bean Validation to the JSF managed bean
Lets get started!
- Use the Maven project created in TOTD #120 and update the directory such that it looks like:
src src/main src/main/java src/main/java/org src/main/java/org/glassfish src/main/java/org/glassfish/samples src/main/java/org/glassfish/samples/SakilaBean.java src/main/java/org/glassfish/samples/SimpleBean.java src/main/java/org/glassfish/samples/SimpleEJB.java src/main/java/org/glassfish/samples/SimpleServlet.java src/main/webapp src/main/webapp/index.jsp src/main/webapp/index.xhtml src/main/webapp/sakila.xhtml src/main/webapp/show.xhtml src/main/webapp/WEB-INF src/main/webapp/WEB-INF/beans.xml src/main/webapp/WEB-INF/web.xml
The key differences are:
- "beans.xml" is an empty file to enable Context & Dependency Injection bean discovery.
- The JPA Persistence Unit is copied and installed in local Maven repository as explained in TOTD #122.
- "web.xml" is added to bootstrap the Java Server Faces runtime. This is required because "@ManagedBean" annotation on "SimpleBean" class is now changed to "@javax.inject.Named". The JSF runtime is automatically registered and booted if any bean in the webapp is annotated with "@ManagedBean" or one of the JSF common classes (such as Converter, Validator, or Renderer) is implemented or extended. If none of these "hints" are available in the application, and it’s required, then it needs to enabled explicitly.
Here are the updated files, changes are highlighted in bold and explained after each fragment:
index.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtm l1-transitional.dtd"> <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> <title>Enter Name & Age</title> </h:head> <h:body> <h1>Enter Name & Age</h1> <h:form> <h:panelGrid columns="3"> <h:outputText value="Name:"/> <h:inputText value="#{simplebean.name}" title="name" id="name" required="true"/> <h:message for="name" style="color: red"/> <h:outputText value="Age:"/> <h:inputText value="#{simplebean.age}" title="age" id="age" required="true"/> <h:message for="age" style="color: red"/> </h:panelGrid> <h:commandButton action="show" value="submit"/> </h:form> </h:body> </html>
Changed the panelGrid from "2" columns to "3". This allows for any validation messages to be displayed right next to the source. Also added "<h:message …/>" to display the validation messages.
SimpleBean.java
package org.glassfish.samples; import javax.inject.Named; import javax.enterprise.context.RequestScoped; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import javax.validation.constraints.Min; @Named("simplebean") @RequestScoped public class SimpleBean { @NotNull @Size(min=2, message="Name must be at least 2 characters") private String name; @NotNull @Min(5) private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
The changes to the above code are listed below:
- Replaced "@ManagedBean" with "@Named" annotation defined in JSR 330 and used by CDI.
- Using constraints defined by Bean Validation APIs (JSR 303) to check for
- Both bean properties to be non-null
- Name to be at least 2 characters
- A minimum age of 5
- There are several other pre-defined constraints in "javax.validation.constraints" package and new constraints can be easily defined as well.
SakilaBean.java
package org.glassfish.samples; import java.util.List; import javax.enterprise.context.RequestScoped; import javax.faces.event.ActionEvent; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.PersistenceUnit; import javax.persistence.EntityManagerFactory; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import sakila.Actor; @Named("sakilabean") @RequestScoped public class SakilaBean { @PersistenceUnit(unitName="SakilaPU") EntityManagerFactory emf; private List<Actor> actors; private int length; private int totalActors; // getters & setters public List<Actor> getActors() { return actors; } public void setActors(List<Actor> actors) { this.actors = actors; } public int getLength() { return length; } public void setLength(int length) { this.length = length; } public int getTotalActors() { return totalActors; } public void setTotalActors(int totalActors) { this.totalActors = totalActors; } public void findActors(ActionEvent evt) { EntityManager em = emf.createEntityManager(); CriteriaBuilder cb = emf.getCriteriaBuilder(); CriteriaQuery<Actor> criteria = cb.createQuery(Actor.class); // FROM clause Root<Actor> actor = criteria.from(Actor.class); // SELECT clause criteria.select(actor); // WHERE clause criteria.where(cb.greaterThan( cb.length(actor.get("firstName").as(String.class)), length)); // FIRE actors = em.createQuery(criteria).getResultList(); totalActors = actors.size(); } }
The key points:
- This is a CDI bean marked by @Named and used in the JSF view (shown next), with the name "sakilabean"
- EntityManagerFactory is injected using @PersistenceUnit
- "findActors" method builds the query using Criteria API. Returns actors’ names limited by the number of characters in their first name.
- Queries "Actor" table from the database and set bean properties "actors" and "totalActors".
- Uses "length" bean property (set from the JSF view) to restrict the number of characters in the name.
sakila.xhtml
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtm l1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>Sakila - Actors Listing</title> </h:head> <h:body> <h1>Sakila - Actors Listing</h1> <h:form> <h:outputText value="Show actors with first name's length <"/> <h:inputText value="#{sakilabean.length}" id="length" required="true" size="5"/> <h:commandButton actionListener="#{sakilabean.findActors}" value="submit"> <f:ajax execute="length" render="actorTable totalActors"/> </h:commandButton><br/> Total actors found: <h:outputText value="#{sakilabean.totalActors}" id="totalActors"/><p/> <h:dataTable var="actor" value="#{sakilabean.actors}" border="1" id="actorTable"> <h:column><h:outputText value="#{actor.firstName}"/>, <h:outputText value="#{actor.lastName}"/></h:column> </h:dataTable> </h:form> </h:body> </html>
Key points:
- This JSF view shows a form that accepts a number used for restricting the length of actors’ first name. The value of this attribute is bound to "length" property of the underlying bean.
- Command Button is tied to a JSF Action Listener which is then bound to "findActors" method in the bean. This method executes the JPA query explained above.
- "f:ajax" is a newly introduced tag in JSF 2.0 and means an Ajax request is performed on the "onClick" event of the rendered button, "findActors" method in the bean in this case. The tag also specifies other tags in the page, "actorTable" and "totalActors" in this case, that needs to be rendered after the request is completed. The input parameter to the Ajax request is specified using "execute" attribute. Read more about this tag here or section 10.4.1.1 of the JSF 2 specification.
Package and deploy the application as:
mvn clean package ./bin/asadmin deploy --force=true ~/samples/javaee6/simplewebapp/target/simplewebapp-1.0-SNAPSHOT.war
The application is now accessible at "http://localhost:8080/simplewebapp-1.0-SNAPSHOT/sakila.jsf" and looks like:
Enter a value of "4" in the text box and hit "Submit":
Only the HTML table of names and the total count of actors is refreshed showcasing partial page refresh.
Now enter a value of "8" and hit "Submit":
Enjoy!
More Java EE 6 features to be shown in subsequent blogs.
Technorati: totd javaee glassfish v3 javaserverfaces ajax jpa cdi beanvalidation
Related posts:- TOTD #120: Deployment Descriptor-free Java EE 6 application using JSF 2.0 + EJB 3.1 + Servlets 3.0
- TOTD #124: Using CDI + JPA with JAX-RS and JAX-WS
- TOTD #158: Java EE 7 JSRs: JPA 2.1, JAX-RS 2.0, Servlets 3.1, EL 3.0, JMS 2.0, JSF 2.2, CDI 1.1, Bean Validation 1.1
- TOTD #148: JPA2 Metamodel Classes in NetBeans 7.0 – Writing type-safe Criteria API
- TOTD #94: A simple Java Server Faces 2.0 + JPA 2.0 application – Getting Started with Java EE 6 using NetBeans 6.8 M1 & GlassFish v3
[Trackback] This post was mentioned on Twitter by arungupta: New Blog: TOTD #123: f:ajax, Bean Validation for JSF, CDI for JSF and JPA 2.0 Criteria API – all in one Java EE 6 … http://bit.ly/coXe5r
Comment by uberVU - social comments — February 16, 2010 @ 2:55 pm
Hi Arun,
Is there anyway I could use f:ajax
to refresh a datatable automatically
at set intervals.
just like a4f:poll did in rich faces.
cheers,
paul.
Comment by paul cunningham — February 18, 2010 @ 6:57 am
Paul,
Let me know if:
http://weblogs.java.net/blog/2009/07/03/tale-two-components-jsf2
serves your purpose ?
-Arun
Comment by Arun Gupta — February 18, 2010 @ 11:56 am
Is there a particular reason you chose to go with a PersistenceUnit/Resource_Local approach vs. PersistenceContext/JTA approach? Thnx,
-NBW
Comment by Noah White — February 23, 2010 @ 6:32 pm
Noah,
The PU was created for a Java SE application and that’s why Resource_Local was used. For a Java EE application, it should be JTA unless the transactions are explicitly managed by the application.
Comment by Arun Gupta — February 23, 2010 @ 9:13 pm