|
In This Issue
These tips were developed using the Java EE 5 SDK. You can download the SDK from the Java EE Downloads page. You can download the sample archive for the Using Java Persistence With JavaServer Faces Technology tip. You can download the sample archive for the Using a Model Facade tip. Any use of this code and/or information below is subject to the license terms. See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms.
JavaServer Faces technology, often abbreviated as JSF, is a framework that simplifies building user interfaces (UIs) for Java Platform, Enterprise Edition (Java EE) and Java 2 Platform, Enterprise Edition (J2EE) applications. The March 24, 2004 Tech Tip, "Introducing JavaServer Faces Technology" gave a brief overview of the technology. It also showed how to create a JSF application that includes GUI components that are modeled by the JSF framework. A later tip showed how to create custom components with JavaServer Faces technology. This tip examines a sample application that uses the Java Persistence API with the JSF framework. A package that contains the code for the sample application accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The Java Persistence API and JSF The Java Persistence API (or simply Java Persistence) simplifies the entity persistence model and adds additional capabilities that were not available in Enterprise JavaBeans (EJB) 2.1 technology. It handles all of the details of how relational data is mapped to Java objects, and it standardizes object-relational mapping. The Java Persistence API is included in the EJB 3.0 specification . There are some JSF features that facilitate the use of Java Persistence in web applications. Value binding expressions bind UI components to model tier data, so that data can be pushed to the model when a form submit occurs. Method binding expressions bind UI components to action methods so that a method attached to a component can execute when that component is activated. For example, when a button is pressed it causes a form to be submitted. Managed beans are JSF application beans that can be instantiated on demand. They are the model tier in a JSF application, and instances of these beans can be stored in a request -- either in session or application scope.
The Java Persistence API also includes an Here's an example of injecting public class BookBean { @PersistenceContext EntityManager em; ... public String placeOrder() { ... em.persist(order); ... } }However that's not a particularly good approach. Here is
a better approach. It uses the public class BookBean { @PersistenceUnit EntityManagerFactory emf; ... public String placeOrder() { ... EntityManager em = emf.createEntityManager(); ... em.persist(order); ... } } JSF Persistence Example If you are familiar with JSF you might also be familiar with the JSF "guess number" application. The application asks the user to guess a number that the application picks within a range of numbers (1-to-10).
The following diagram shows the flow of the guess number application:
The application begins with the display of an HTML page that prompts for a number between a range. After entering a number, the user presses the "Guess" button to submit the information. If the user submits a number that is outside the range, or submits an invalid digit (a letter, for example), the application displays a validation error message from JSF. If the user submits a valid number, the "response" page appears indicating whether the guess is correct or not. The response page also displays an "Again" button. Pressing this button navigates back to the initial page to allow more guesses. A user can navigate back and forth between the pages until he makes a correct guess. If the user presses the "Again" button after making a correct guess it implicitly starts a new game. Java Persistence is used to store in a database all the guess attempts, and it is used to display (or play back) guess attempts that have been stored in the database. Let's take a look at some of the code for the guess number application. Here is the script that creates the database table: create table USERGUESS (ID INT NOT NULL, GUESS VARCHAR(10) NOT NULL, OUTCOME VARCHAR(10) NOT NULL, PRIMARY KEY(ID));
Here is an entity class, ... import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class UserGuess implements java.io.Serializable { @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; private String guess; public String getGuess() { return guess; } public void setGuess(String guess) { this.guess = guess; } private String outcome; public String getOutcome() { return outcome; } public void setOutcome(String outcome) { this.outcome = outcome; } }
The
A JSF managed bean,
This application uses a container-managed ... public class UserNumberBean { ... // This injects the default entity manager factory @PersistenceUnit private EntityManagerFactory emf; // This injects a user transaction object. @Resource private UserTransaction utx; ...
You can use the injected ... public class UserNumberBean { ... /∗∗ ∗ This method persists each attempted guess (number). ∗/ private String sameGame() { String message = null; EntityManager em = null; try { em = emf.createEntityManager(); utx.begin(); em.persist(userGuess); utx.commit(); } catch (Exception ee) { try { utx.rollback(); } catch (Exception re) {} if (logger.isLoggable(Level.SEVERE)) { logger.log(Level.SEVERE, "Database Error:", ee.getCause()); } message += "Database Error: "+ee.getCause(); } finally { if (em != null) { em.close(); } } return message; } ... /∗∗ ∗ This method clears the database table in preparation ∗ of a new game. ∗/ private String newGame() { String message = null; EntityManager em = null; String statement = "delete from UserGuess"; try { em = emf.createEntityManager(); utx.begin(); em.createQuery(statement).executeUpdate(); utx.commit(); } catch (Exception ee) { try { utx.rollback(); } catch (Exception re) { } if (logger.isLoggable(Level.SEVERE)) { logger.log(Level.SEVERE, "Database Error:", ee.getCause()); } message = "Database Error: "+ee.getCause(); } finally { if (em != null) { em.close(); } } return message; } ...Posting From The Client
The initial page has a text field for entering a number and a button labeled "Guess" for submitting the guess. Here is a snippet of the ... <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> ... <h:inputText id="userNo" label="User Number" value="#{UserNumberBean.userNumber}" validator="#{UserNumberBean.validate}"/> <h:commandButton id="guess" action="success" value="Guess" /> <h:dataTable border="1" rendered="#{UserNumberBean.hasGuesses}" value="#{UserNumberBean.guessList}" var="guessItem"> <h:column> <f:facet name="header"> <h:outputText value="Guess" /> </f:facet> <h:outputText value="#{guessItem.guess}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Outcome" /> </f:facet> <h:outputText value="#{guessItem.outcome}"/> </h:column> </h:dataTable> ...
The ... public class UserNumberBean { ... // Indicates that we have some attempted guesses. private boolean hasGuesses = false; ... /∗∗ ∗ -- Accessor methods for the ∗ property (used to control rendering of the ∗ ∗/ public void setHasGuesses(boolean hasGuesses) { this.hasGuesses = hasGuesses; } public boolean getHasGuesses() { return hasGuesses; } ...
The expression " ... public class UserNumberBean { ... // The attempted guesses. private Collection <UserGuess> guessList; ... /∗∗ ∗ This method loads the ∗ database. The ∗ ∗/ public Collection <UserGuess> getGuessList() { EntityManager em = emf.createEntityManager(); guessList = em.createQuery() "select g from UserGuess g").getResultList(); return guessList; } ...
The Running the Sample Code A sample package accompanies this tip that demonstrates the techniques covered in the tip. You can deploy the sample package on any web container that supports the Servlet 2.5 API, JavaServer Pages (JSP) Technology 2.1, and JavaServer Faces Technology 1.2. These instructions also assume that you are using the Java EE 5 SDK. To install and run the sample:
Add $JAVA_HOME/bin and $JAVAEE_HOME/bin to your PATH
environment variable.
About the Author Roger Kitain is the JavaServer Faces technology co-specification lead. He has been extensively involved with server-side web technologies and products since 1997. Roger started working on JavaServer Faces technology in 2001 as a member of the reference implementation team. He has experience with Servlet and JSP technologies. Most recently, Roger has been involved with different rendering technologies for JavaServer Faces technology.
A number of recent Tech Tips, including the other tip in this issue, "Using Java Persistence With JavaServer Faces Technology," have covered various aspects of the Java Persistence API. What's significant is that you can use the Java Persistence API to manage persistence in the domain model of your Java EE 5 applications and take advantage of additional capabilities that were not available in the J2EE platform. However there are a number of things to consider when you use
Java Persistence. For example, a Java Persistence client such as a servlet, JSP page, or a JSF managed bean, might need to access
various types of APIs to access entities in the model. (In this tip, the term "client" refers to web components such as JSF
managed beans, servlets, or JSP pages that call methods on Java Persistence entity objects.) These APIs include Java Transaction
(JTA) APIs, As your application grows, you might need to repeat the same code for access to multiple entities. This might involve copying similar data access logic into each servlet or managed bean that needs to access the entities. Not only is this repetitive code difficult to manage, but it tightly couples the code to the entity model.
A Model Facade is a good way to simplify the code in a Java Persistence client. What is a Model Facade? A Model Facade (or simply a "Facade") is a design pattern. The Facade pattern defines a higher-level class that encapsulates and centralizes the interactions between Java Persistence clients and the entities and operations of the Java Persistence API. The pattern provides a single interface for operations on a set of entities. Using the Facade pattern can make the code in your Java Persistence clients cleaner. A web component that uses a Facade to access the model tier does not have to be aware of all the details of the APIs for each entity. Neither does the web component need to be aware of the persistence mechanisms being used when accessing the entity managers or transaction managers. Also, if you add a Facade between the calling clients and the entities in the model tier, it makes your code more loosely-coupled and easier to maintain.
A Facade isn't limited to use with Java Persistence. It's also useful with other persistence technologies such as JDBC. Designing and Coding a Facade To illustrate how much cleaner it is to code with a Facade, let's look at a "before" and "after" example. The "before" example shows the code for a servlet that accesses entities in a model tier. The "after" example shows the servlet code if a Facade is used. Here is the "before" code: public class MyWebClient ... { ... public void doGet(HttpServletRequest request, HttpServletResponse response) { ... //processing a web request to //add a new Item to the database if (selectedURL.equals("additem.do")) { String desc = request.getParameter("item_desc"); String name = request.getParameter("item_name"); ... Item item = new Item(); item.setName(name); item.setDescription(desc); //now access entities in model tier EntityManager em = emf.createEntityManager(); try{ utx.begin(); em.joinTransaction(); em.persist(item); utx.commit(); } catch(Exception exe){ System.out.println("Error persisting item: "+exe); try { utx.rollback(); } catch (Exception e) {} } finally { em.close(); } } ... Here is the "after" code: public class MyWebClient { ... ... public void doGet(HttpServletRequest request, HttpServletResponse response) { ... //processing a web request to //add a new Item to the database if (selectedURL.equals("additem.do")) { String desc = request.getParameter("item_desc"); String name = request.getParameter("item_name"); ... Item item = new Item(); item.setName(name); item.setDescription(desc); //now access entities in model tier MyModelFacade myfacade = new MyModelFacade(); myfacade.addItem(item); }
One strategy to implement a Facade is to use a web component as the An Example Facade for a Web-Only Application Let's take a look at the code for a Facade. You can find the source code for the Facade as well as the code for the other examples in this tip in the sample application package that accompanies the tip. public class CatalogFacade implements ServletContextListener { @PersistenceUnit(unitName="CatalogPu") private EntityManagerFactory emf; @Resource UserTransaction utx; public CatalogFacade(){} public void contextDestroyed(ServletContextEvent sce) { if (emf != null && emf.isOpen()) { emf.close(); } } public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); context.setAttribute("CatalogFacade", this); } public void addItem(Item item) throws InvalidItemException { EntityManager em = emf.createEntityManager(); if(item.getName().length() == 0) throw new InvalidItemException("The item" + " name cannot be empty. Please specify a name for the item. "); try { utx.begin(); em.joinTransaction(); em.persist(item); utx.commit(); } catch(Exception exe){ System.err.println(exe); try { utx.rollback(); } catch (Exception e){ e.initCause(exe); throw new RuntimeException(e); } throw new RuntimeException(exe); } finally { if (em != null) { em.close(); } } } public Item getItem(int itemID){ EntityManager em = emf.createEntityManager(); Item item = em.find(Item.class,itemID); em.close(); return item; } public List<Item> getAllItems(){ EntityManager em = emf.createEntityManager(); List<Item> items = em.createQuery() "SELECT OBJECT(i) FROM Item i").getResultList(); em.close(); return items; } }
There are a couple design choices to notice in the
Notice too that in the Using the Facade Now let's look at how a web component such as a servlet uses the example Facade. public class CatalogServlet extends HttpServlet { private CatalogFacade cf; private ServletContext context; private Map nameSpace; public void init(ServletConfig config) throws ServletException { context = config.getServletContext(); cf = (CatalogFacade)context.getAttribute("CatalogFacade"); initPathMapping(); } ... public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ... try { if (selectedURL.equals("additem.do")) { //get values from request and set in a //new Item to then add to database String desc = request.getParameter("item_desc"); String name = request.getParameter("item_name"); ... Item item = new Item(); item.setName(name); item.setDescription(desc); ... cf.addItem(item); //now call Facade ... } }
The servlet uses the By using the Facade, the servlet is shielded from the details of the entities and from any persistence operations required to access the entities. Running the Sample Code A sample package accompanies this tip that includes a Model Facade. To install and run the sample:
Click on the links in the displayed page to retrieve or add items in a catalog. If you examine the source for the application, you'll see that it uses a Model Facade as the interface for operations on the persistent entities in the catalog. Summary If you are building a Java EE 5 web application that uses the Java Persistence API, consider refactoring your code by introducing a Model Facade. For additional information about Facades and the Java Persistence API see:
About the Authors Sean Brydon is an engineer with Sun Microsystems where he is the technical lead for the Java BluePrints program. He has been involved with the Java BluePrints since its inception. He is an author of the Addison-Wesley Java-series books, "Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition," and "Designing Web Services with the J2EE 1.4 Platform." He is a regular speaker on enterprise application design. Yutaka Yoshida was a Servlet 2.4 specification lead, and is currently working in the Java BluePrints project. He has been involved in designing and developing the Java Adventure Builder reference application, the Java BluePrints Solutions Catalog, and the Java Pet Store 2.0 reference application. Developer Assistance
Need programming advice on Java EE? Try Developer Expert Assistance. Java EE SDK Contest
Download the Java EE SDK. Then enter the Java EE SDK Contest and get a chance to win an iPod Nano. The contest ends November 30. | ||||||||||||||
|
| ||||||||||||