Search |
||||||||||||||||||||||||||
Extending the NetBeans Tutorial JSF-JPA-Hibernate Application, Part 1 - Co-ordinating JSF View Parameter Passing to Managed BeanPosted by maxpoon on June 13, 2007 at 12:47 PM PDT
BackgroundThe NetBeans tutorial "Using Hibernate With the Java Persistence API" nicely demonstrates, by using the NetBeans IDE, easy construction of :
The follow-up tutorial "NetBeans Wiki - UsingHibernateWithJPA" further shows usage of JPA as well as Hibernate-specific facilities, including :
While the above-mentioned two tutorials demonstrate ease of JSF-JPA-Hibernate application construction with usage of JPA and Hibernate facilities in the persistence-tier, it is interesting to explore also on the flexibility and power of JSF in the web-tier. Extending The Sample ApplicationBased on the "Using Hibernate With the Java Persistence API" tutorial (but choosing the sample database tables ProductCode, Product, and Manufacturer instead of Customer and DiscountCode), our JSF-JPA-Hibernate sample application (let's call it 'SimpleJpaHibernateApp') can be created. (Please refer to the original tutorial for other details of software needed and environment set-up).
This can be done easily in JSFAn quite obvious way is to get the selected ProdCode in the "Detail of ProductCode" page, stored in JSF EL :
as shown in the Coding Listing 1, for reference by the subsequently invoked action
which is simpleJpaHibernateApp/web/product/List.jsp (shown in the following Code Listing 2) as defined in faces-config.xml.
of the managed bean simpleJpaHibernate.controller.ProductController.
respectively, we shall be able to re-use simpleJpaHibernateApp/web/product/List.jsp to display a table of Products with the selected ProdCode. Step 1 - Add New JSF CommandLink in "Detail of ProducCode" Page to Pass the Selected ProdCode to New Bean Method in ProductController
|
||||||||||||||||||||||||||
| Code Listing 3 - New <h:commandLink...> added to "Detail of ProductCode" page - simpleJpaHibernateApp/web/productCode/Detail.jsp |
| .... <h:commandLink action="productCode_list" value="Show All ProductCode"/> <br> <h:commandLink action="#{product.setSelectedProdCodeDisplayProducts}" value="List of Product with this ProductCode"> <f:param name="selectedProdCode" value="#{productCode.productCode.prodCode}"/> </h:commandLink> <br> <a href="/SimpleJpaHibernateApp/index.jsp">Back to Home Page</a> .... |
The 'passed-in' FacesContext selectedProdCode parameter is to be retreived by ProductController with the following new method setSelectedProdCodeDisplayProducts()
| Code Listing 4 - New bean methods setSelectedProdCode(String selectedProdCode) and setSelectedProdCodeDisplayProducts() of simpleJpaHibernateApp.controller.ProductController |
/** * Setter for selectedProdCode property * @param selectedProdCode String PROD_CODE column value of the selected * ProducCode e.g. in productCode/Detail.jsp */ public void setSelectedProdCode(String selectedProdCode) { this.selectedProdCode = selectedProdCode; } /** * setSelectedProdCodeDisplayProducts() : * <ol> * <li>Get 'selectedProdCode' parameter from FacesContext</li> * <li>Set bean property 'selectedProdCode' with the parameter value</li> * <li>Return "product_list" to invoke product/List.jsp as defined in * faces-config.xml to display Products with this selectedProdCode</li> * </ol> */ public String setSelectedProdCodeDisplayProducts() { String _selectedProdCode = (String) FacesContext.getCurrentInstance() .getExternalContext().getRequestParameterMap() .get("selectedProdCode"); setSelectedProdCode(_selectedProdCode); return "product_list"; } |
Also, the getProducts() and getItemCount() methods are required to be modified to get the 'selectedProdCode-aware' query behaviour :
| Code Listing 5 - Modified managed bean methods getProducts() and getItemCount() of simpleJpaHibernateApp.controller.ProductController |
/** * Retrieve Products and return as ListDataModel according to: * <ol> * <li>ProductCode selected already * <code> * (selectedProdCode != null && selectedProdCode.length() != 0) * </code> * => retrieve Products with the selected ProductCode * </li> * <li>ProductCode not selected (otherwise) * => retrieve all Products * </li> * </ol> */ public DataModel getProducts() { EntityManager em = getEntityManager(); try{ Query q; if (selectedProdCode != null && selectedProdCode.length() != 0) { q = em.createQuery("select object(o) from Product as o " + "where o.productCode.prodCode = :selectedProdCode") .setParameter("selectedProdCode", selectedProdCode); } else { q = em.createQuery("select object(o) from Product as o"); } q.setMaxResults(batchSize); q.setFirstResult(firstItem); model = new ListDataModel(q.getResultList()); return model; } finally { em.close(); } } /** * Count no. of Products items according to: * <ol> * <li>ProductCode selected already * <code> * (selectedProdCode != null && selectedProdCode.length() != 0) * </code> * => count number of Products with the selected ProductCode * </li> * <li>ProductCode not selected (otherwise) * => count number of all Products * </li> * </ol> */ public int getItemCount() { EntityManager em = getEntityManager(); try{ Query q; if (selectedProdCode != null && selectedProdCode.length() != 0) { q = em.createQuery("select count(o) from Product as o " + "where o.productCode.prodCode = :selectedProdCode") .setParameter("selectedProdCode", selectedProdCode); } else { q = em.createQuery("select count(o) from Product as o"); } int count = ((Long) q.getSingleResult()).intValue(); return count; } finally { em.close(); } } |
Basically, the addition of new query based on the selected ProdCode (as criteria) passed from previous "Detail of ProductCode" JSF page / view (based also on modification/re-use of existing "Listing Products" view) is completed.
However, also due to the introduction of new query behaviour to the "Listing of Products" view, there are a few subsequent amendments to the application needed.
This includes the requirement to reset the newly introduced bean property selectedProdCode of ProductController in case of invocation from the application home page, to display all available Products in the database as expected. Again, this can be done by the very same JSF CommandLink, this time with "" for the selectProdCode parameter :
| Code Listing 6 - Modified index.jsp |
| <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%-- index.jsp - Modified from index.jsp_orig to use JSF <h:commandLink ...> to clear any previously set ProductController#selectedProdCode for listing Products via 'product_list' action @author Max Poon (maxpoon@dev.java.net) --%> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Simple JPA Hibernate Application</title> </head> <body> <f:view> <h:messages errorStyle="color: red" infoStyle="color: green" layout="table"/> <h1>Simple JPA Hibernate Application</h1> <h:form> <br/> <h:commandLink value="List of ProductCode" action="productCode_list"/> <br/> <h:commandLink value="List of Product" action="#{product.setSelectedProdCodeDisplayProducts}"> <f:param name="selectedProdCode" value=""/> </h:commandLink> <br/> <h:commandLink value="List of Manufacturer" action="manufacturer_list"/> </h:form> </f:view> </body> </html> |
This requires configuration / invocation of the new index.jsp as JSF View via the application's web.xml servlet-mapping :
| Code Listing 7 - Example new servlet-mapping required in web.xml |
| .... <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> .... |
with all correspondingly links to the SimpleJpaHibernateApp home page modified from index.jsp to index.jsf, i.e. :
| Code Listing 8 - Modified href link to "Home Page" in all referencing JSP's |
| .... <%-- Modified link from /SimpleJpaHibernateApp/index.jsp to /SimpleJpaHibernateApp/index.jsf --%> <a href="/SimpleJpaHibernateApp/index.jsf">Back to Home Page</a> .... |
For completeness' sake in this case, we should also have an index.html (suggested to be set as welcome-file in web.xml) so that requesting :
will be automatically redirected to the correct SimpleJpaHibernateApp home page
So, SimpleJpaHibernateApp is now ready for compilation, deployment and testing, e.g. by clicking "List Product with this ProductCode" from "Detail of ProductCode" page with ProductCode as, e.g. "HW", and you should get :
| Figure 6 - "Listing Products" Page for "HW" ProductCode |
while clicking "List of Product" on the Home Page, you should get all the available Products for ProdCode "SW", "HW", etc.
| Figure 7 - "Listing Products" Page for All ProductCodes, i.e. All Available Products |
If you can get the above query views working, congratulations! Your SimpleJpaHibernate should be working fine, and ready for your further exploration!
In coming (hopefully soon) "Extending the NetBeans Tutorial JSF-JPA-Hibernate Application, Part 2", I would like to share on enabling JMX monitoring on Hibernate 3.2.x, and on the latest Ehcache 1.3.0 with full JMX support and detail per-cache monitoring statistics (yes, it's great!) - using our SimpleJpaHibernateApp as example (thanks to Ehcache's creator and maintainer Greg Luck for his helping me get the JMX monitoring on Ehcache working for the SimpleJpaHibernateApp, when we met at JavaOne May this year)
Stay tuned!
|