General | Thursday, February 11, 2010

TOTD #123: f:ajax, Bean Validation for JSF, CDI for JSF and JPA 2.0 Criteria API - all in one Java EE 6 sample application

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!



  1. 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:

    1. "beans.xml" is an empty file to enable Context & Dependency Injection bean discovery.
    2. The JPA Persistence Unit is copied and installed in local Maven repository as explained in TOTD #122.
    3. "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 &amp; Age</title>
</h:head>
<h:body>
<h1>Enter Name &amp; 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 &lt;"/>
<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

Join the discussion

Comments ( 10 )
  • uberVU - social comments Tuesday, February 16, 2010
    [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
  • paul cunningham Thursday, February 18, 2010

    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.


  • Arun Gupta Thursday, February 18, 2010

    Paul,

    Let me know if:

    http://weblogs.java.net/blog/2009/07/03/tale-two-components-jsf2

    serves your purpose ?

    -Arun


  • Noah White Tuesday, February 23, 2010

    Is there a particular reason you chose to go with a PersistenceUnit/Resource_Local approach vs. PersistenceContext/JTA approach? Thnx,

    -NBW


  • Arun Gupta Tuesday, February 23, 2010

    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.


  • guest Sunday, May 15, 2011
    Is there a way when you click the button after fill inputtext feild, some other inputtext feilds from another page(xhtml) show in the same page or at the buttom. if any body know please help me.
    Thank you.
  • Arun Gupta Monday, May 16, 2011
    guest,
    If you know the backing bean for the other XHTML page then you may be able to show the data in this page. Just create a new outputText field and bind it to that value.
  • leader Monday, May 16, 2011
    I mean can I use xmlhttp in my xhtml or not?
    I know I can do with jsp but I want to used with jsf 2.0.
    like this code Can I used in my index.xhtml?
    <script type="text/javascript">
    function showUser(str)
    {
    if (str=="")
    {
    document.getElementById("txtHint").innerHTML="";
    return;
    }
    if (window.XMLHttpRequest)
    {// code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
    }
    else
    {// code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange=function()
    {
    if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
    }
    }
    xmlhttp.open("GET","getuser.xhtml?q="+str,true);
    xmlhttp.send();
    }
    </script>
    </head>
  • leader Monday, May 16, 2011
    I need to know how you click a buttom another form from onather page displays at the buttom of my main page. I know how to do this in php or jsp but I want to know how to with jsf 2.0
    Thank you very much
  • Arun Gupta Tuesday, May 17, 2011
    leader,
    Please follow up with your questions on webtier@glassfish.java.net for the benefit of a broader audience.
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
 

Visit the Oracle Blog

 

Contact Us

Oracle

Integrated Cloud Applications & Platform Services