PrimeFaces in the Enterprise

by Josh Juneau

Build data-driven applications for the enterprise using the PrimeFaces JavaServer Faces UI framework.

Published April 2014

PrimeFaces, a popular JavaServer Faces (JSF) UI framework, can be used to quickly develop sophisticated applications for the enterprise or for standard websites. This article focuses on how to efficiently build data-driven applications for the enterprise using PrimeFaces.

In this article, we'll be developing an enterprise application, making use of PrimeFaces to create a user-friendly, robust experience. The application we will be developing is called AcmePools, and it is for a swimming pool installation company named Acme Pools. It is our job to develop forms to input customer, job, and pool information, as well as provide the ability to easily retrieve and update the data, as needed.

Note: You can find the source code for the AcmePools application on GitHub.

Zero Configuration for Getting Started

Traditional JSF applications are easy to create and configure. One of the biggest boons of JSF has always been easy configuration, and integrating PrimeFaces into a JSF application is no different. The only requirement is to add the PrimeFaces library to a standard JSF application—that's it. There are some minor optional configurations for utilizing additional features within PrimeFaces, such as file upload and custom templating. However, to get started right away, no additional configuration is necessary. NetBeans IDE 8 makes it even easier, with the ability to generate PrimeFaces application pages from entity classes. This article demonstrates how to generate a PrimeFaces application using the NetBeans IDE 8 features, and then progressively customize the application making it more sophisticated.

Creating the Application

For the context of this article, we'll be using a NetBeans IDE 8 Maven-based web project. To get started, generate the database tables and sequences that will be used by the AcmePools application. You can do this within NetBeans by starting the default database that comes with NetBeans: Java DB, which is Oracle's supported distribution of the Apache Derby open source database. Then, in the Services window, expand the Databases tree, right-click Java DB, and select Start Server.

For this article, all SQL code will be executed within the sample schema, which is configured and ready to go; we'll be adding only a couple of additional tables. Double-click the sample schema database connection within the Databases tree to connect to the database. Right-click the connection and select Execute Command, which will open up a SQL session with the database. Copy and paste the SQL code that is contained within the create_database.sql file that is part of the source code for this article, and execute it using the green arrow icon in the SQL editor (see Figure 1).

primefaces-f1

Figure 1: Creating the database

Next, create a new Maven web application project (see Figure 2).

primefaces-f2

Figure 2: Creating a Maven-based web application in NetBeans

Enter AcmePools for the project name, and choose a project location on your file system. Enter com.acme for Group ID, enter com.acme.acmepools for Package Name, and click Next.

In the next dialog box, select the application server of your choice. Be sure to use an application server such as GlassFish 4.0 or WildFly, which are compatible with Java EE 7.

Next, set the Java EE Version to Java EE 7. Click Finish to create the application project.

To manually add PrimeFaces as a dependency, expand the newly created project, right-click the Dependencies item and choose Add Dependency (see Figure 3).

primefaces-f3

Figure 3: Adding a PrimeFaces Maven dependency

In the Add Dependency dialog box, type PrimeFaces into the Query field. Expand the org.primefaces item within the search results, and choose 4.0 [jar] - central or 5.0 [jar] - central, and then click Add.

Next, enable the JSF framework within the Maven web application project. This can be done by right-clicking the project, choosing Properties, and then clicking the Frameworks category and adding JavaServer Faces (Figure 4). This automatically adds the appropriate configuration to the project's web.xml file and creates an index.xhtml welcome file as a starting point for your JSF application.

primefaces-f4

Figure 4: Adding the JSF framework to your project

Since PrimeFaces has been added as a Maven dependency, any new XHTML files that are created will be ready to use with PrimeFaces, because the appropriate namespace will be added by default.

Populating and Capturing Data

PrimeFaces makes the development of user-input forms simple. We all know that it is pertinent to validate user input and provide appropriate notifications to the user when something goes wrong. PrimeFaces contains a number of input components to help you develop robust data-input forms. NetBeans IDE 8.0 provides support for easy development of CRUD (create, read, update, delete) applications using NetBeans. This example will demonstrate how to use this support to create the initial input forms and data tables for the AcmePools application.

To begin, create a new package within the project named com.acme.acmepools.entity. Take advantage of the NetBeans IDE by using the Entity Classes from Database feature (see Figure 5). To do this, right-click the newly created package, select New, and then select Entity Classes from Database. Then select the appropriate data source and choose the CUSTOMER, POOL_CUSTOMER, JOB, and POOL tables.

Note: Be sure to deselect the Include Referenced Classes checkbox, because we do not wish to generate pages from the other associated database tables.

primefaces-f5

Figure 5: Creating entity classes from the database

Click Next and retain the default selections, making sure that you create a persistence unit. Click Next again, and then click Finish. Each of the database tables should now have an associated entity class.

Now that the entity classes have been created, generate the JSF views by right-clicking the project's Web Pages folder and choosing New and then JSF Pages from Entity Classes. When the dialog box opens, select each of the newly created entity classes, and then choose Next.

On the next screen, retain all of the default values with the exception of the Choose Templates option; for that option, select PrimeFaces rather than the default. Click Finish, and NetBeans will create three separate folders within the Web Pages folder, each named accordingly for their associated entity classes. Within each folder, the following JSF pages are created: Create.xhtml, Edit.xhtml, List.xhtml, and View.xhtml. NetBeans also automatically generates JSF controllers and Enterprise JavaBeans (EJB) beans for each of the entity classes, and the newly generated pages are wired up to the controllers and ready for use.

Note: At this point, take a moment to organize the code by separating the EJB session beans, controller, and entity classes into their own packages. Use NetBeans IDE to move and refactor the classes once you've generated the new package structure. The example application uses the packages com.acme.acmepools.session, com.acme.acmepools.jsf, and com.acme.acmepools.entity, respectively.

At this point, you can build the application, and then you can deploy it by right-clicking the project and choosing Run. Initially, all that will be displayed is the layout that is shown in Figure 6.

primefaces-f6

Figure 6: Default index.xhtml page

Note: It is important to note that automatic primary key generation is not enabled by default. Specify the @GeneratedValue and @SequenceValue annotations within your entity classes, along with a database sequence to configure automatic primary key generation.

Clicking one of the links in the index.xhtml view navigates to the List.xhtml view for the chosen entity.

First things first, though. Let's make the views more recognizable. Open the bundle.properties file, which in NetBeans is located within the project's "Other Sources" -> src/main/resources -> <default package> package. Each of the properties within the file corresponds to an entity view within the application. Change the properties accordingly so that you can recognize which view you have selected. For instance, update the ViewCustomerTitle property to read View Customer, and update the ListCustomerTitle property to read List Customer.

Although the wizard generates these forms for you, some customization is required to make them more user-friendly. For instance, if you open the PoolCustomer List.xhtml view and then click the Create button, you'll see lists for CustomerId and PoolId objects. By default, the names are not recognizable, but you can alter the code to ensure recognizable values are displayed by editing the poolCustomer -> Create.xhtml markup and changing the f:selectItem attributes within the PrimeFaces SelectOneMenu components to display a label. Listing 1 shows the code for enhancing these components.

<p:outputLabel value="#{bundle.CreatePoolCustomerLabel_customerId}" for="customerId" />
<p:selectOneMenu id="customerId" value="#{poolCustomerController.selected.customerId}" >
    <f:selectItems value="#{customerController.itemsAvailableSelectOne}"
                               var="customerIdItem"
                               itemLabel="#{customerIdItem.name}"
                               itemValue="#{customerIdItem}"/>
</p:selectOneMenu>
<p:outputLabel value="#{bundle.CreatePoolCustomerLabel_poolId}" for="poolId" />
<p:selectOneMenu id="poolId" value="#{poolCustomerController.selected.poolId}" >
    <f:selectItems value="#{poolController.itemsAvailableSelectOne}"
                               var="poolIdItem"
                               itemLabel="#{poolIdItem.style}"
                               itemValue="#{poolIdItem}"/>
</p:selectOneMenu>

Listing 1: Adding the itemLabel attribute to <f:selectItems>

After adding the itemLabel attributes, the lists will be more easily readable, as shown in Figure 7.

primefaces-f7

Figure 7: Custom labels for SelectOneMenu items

You can customize other pages and components as needed, making the application easier to use.

Creating a Custom Index Page

The default index page for the NetBeans-generated PrimeFaces application is very plain. To create a more informative and useful home page, begin by applying the application template to the index.xhtml page. To do so, add the Facelets, PrimeFaces, and JSF Core namespaces into the view, and make use of <ui:composition> and <ui:define> to generate a view that adheres to the template:

xmlns:p="http://primefaces.org/ui"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"

Let's also add a more useful data set to the body of the index page by adding the customer listing inside the <ui:define name="body"> section. To do so, add a PrimeFaces DataTable component to the view. The key attributes of the p:dataTable element for creating a simple data table are value and var. The value attribute should specify a collection of data residing within the managed bean controller, which will be displayed within the table. The var attribute is used to reference each separate record within the table. In Listing 2, var is set to item, and by doing so we can reference each separate table record in more detail.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <ui:composition template="/template.xhtml">

        <ui:define name="title">
            <h:outputText value="Acme Pools"></h:outputText>
        </ui:define>

        <ui:define name="body">
            <h:form id="IndexForm">
                <p:panel header="Acme Pools Customer Listing">
                    <p:dataTable id="datalist" value="#{customerController.items}" 
var="item"    
                                 paginator="true"
                                 rowKey="#{item.customerId}"
                                 rows="10"
                                 rowsPerPageTemplate="10,20,30,40,50"
                                 >
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Customer ID"/>
                            </f:facet>
                            <h:outputText value="#{item.customerId}"/>
                        </p:column>
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Customer Name"/>
                            </f:facet>
                            <h:outputText value="#{item.name}"/>
                        </p:column>
                       
                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Customer Email"/>
                            </f:facet>
                            <h:outputText value="#{item.email}"/>
                        </p:column>
                        
                      
                    </p:dataTable>
                </p:panel>
            </h:form>
        </ui:define>
    </ui:composition>

</html>

Listing 2: Adding Facelets template and PrimeFaces DataTable to index.xhtml

To inspect the code a bit further, look in the CustomerController class, and find the items property (see Listing 3). If you are using the NetBeans IDE, you can hold down the Command key (for Mac OS X) or the Control key (for Microsoft Windows) and click the items reference within the #{customerController.items} expression to be automatically redirected to the property within the controller.

public List<Customer> getItems() {
        if (items == null) {
            items = getFacade().findAll();
        }
        return items;
}

Listing 3: Managed bean property for populating the Customer data table

After inspecting the code, you can see that a List<Customer> is used to populate the p:dataTable component within the view. The new index page looks like Figure 8.

primefaces-f8

Figure 8: Newly constructed index page

Displaying and Editing Records

As seen in the previous section, one of the most efficient ways to display records of data is to list each of them within a table. Have you ever worked on a web application that required you to click a row in a table in order to edit the data, which then took you to a separate edit page? Gone are the days of multiple page navigations to accommodate simple tasks. The pages that were generated for this application by default via NetBeans contain the functionality to show the content of different views as modal dialog boxes, allowing users to stay within a single page to add or change data. This is made possible using the PrimeFaces JavaScript API to bind actions to buttons, applying those actions to specified PrimeFaces components.

For instance, the Create button on the PoolCustomer List.xhtml view is coded as follows:

<p:commandButton id="createButton" icon="ui-icon-plus"
   value="#{bundle.Create}" 
   actionListener="#{poolCustomerController.prepareCreate}"
   update=":PoolCustomerCreateForm"
   oncomplete="PF('PoolCustomerCreateDialog').show()"/>

Listing 4 shows the code for the prepareCreate method of the PoolCustomerController class. The code generates a new PoolCustomer object, which can then be populated by the user and inserted into the database. This method could be customized to suit your application needs.

public PoolCustomer prepareCreate() {
    selected = new PoolCustomer();
    initializeEmbeddableKey();
    return selected;
}

Listing 4: The prepareCreate method of the PoolCustomerController class

The oncomplete attribute contains a PrimeFaces JavaScript action to open the PrimeFaces component identified as PoolCustomerCreateDialog, which is located within the PoolCustomer Create.xhtml view. To associate an identifier with a PrimeFaces component, specify a value for the component's widgetVar attribute. When the button is clicked, the prepareCreate method of the PoolCustomerController class is invoked, and the creation dialog box is displayed when the method is finished. The update attribute specifies that the PoolCustomerCreateForm should be asynchronously updated.

The PrimeFaces DataTable component can be customized very easily, making it easy to develop a highly sophisticated table for displaying and updating application data. For example, the PrimeFaces DataTable component provides various options for editing without leaving the table view. If you take a look at the List views that were generated for the AcmePools project by NetBeans, you will see that the DataTable components have been customized to add selection listeners. For instance, Listing 5 shows the DataTable that is included within the customer/List.xhtml view.

<p:dataTable id="datalist" value="#{customerController.items}" 
        var="item" selectionMode="single"
        selection="#{customerController.selected}"
        paginator="true"
        rowKey="#{item.customerId}"
        rows="10"
        rowsPerPageTemplate="10,20,30,40,50">
     <p:ajax event="rowSelect"   update="createButton viewButton editButton 
deleteButton"/>
     <p:ajax event="rowUnselect" update="createButton viewButton editButton 
deleteButton"/>
...
</p:dataTable>

Listing 5: DataTable selection

The selectionMode attribute indicates that a single row will be selected; this could also be set to "multiple" to indicate that many rows can be selected at once. The selection attribute is used to specify the object within the managed bean controller to which the selected record item will be assigned. In this case, it is a Customer object, as seen within the CustomerController class:

private Customer selected;
...
public Customer getSelected() {
    return selected;
}

PrimeFaces <p:ajax> elements can be embedded inside other PrimeFaces components to apply asynchronous functionality. In this case, when a row is either selected or deselected, the buttons within the view are updated. In the application, if you select a row and then scroll to the bottom of the page, you have the opportunity to edit, view, or delete the record. In Figure 9, a record has been selected and then the Edit button has been chosen.

primefaces-f9

Figure 9: Edit Customer dialog box

Note: When using NetBeans IDE 8, you can see the PrimeFaces documentation for any component by using the autocompletion feature within the editor (see Figure 10).

primefaces-f10

Figure 10: NetBeans IDE's PrimeFaces code completion functionality

The NetBeans IDE wizard has generated a fully functional CRUD application, but what if your customers had hundreds of record to edit? This could take a while to do if each row had to be selected, a button had to be clicked, and then edits needed to be made. The PrimeFaces DataTable cell editing feature makes it easier to edit the data contained within a table.

To add cell editing capability to the customer/List.xhtml table, add the editable and editMode attributes to the dataTable element, as follows:

<p:dataTable id="datalist" value="#{customerController.items}" 
             var="item"
             selectionMode="single" selection="#{customerController.selected}"
             editable="true" editMode="cell"
             paginator="true"
             rowKey="#{item.customerId}"
             rows="10"
             rowsPerPageTemplate="10,20,30,40,50">

Next, as shown in Listing 6, use the p:cellEditor element to mark each row that you wish to make editable, and also indicate how the output is to be displayed (via f:facet name="output") and indicate how to treat input (via f:facet name="input"):

<p:column>
    <f:facet name="header">
        <h:outputText value="#{bundle.ListCustomerTitle_addressline1}"/>
    </f:facet>
    <p:cellEditor>
        <f:facet name="output">
            <h:outputText value="#{item.addressline1}"/>
        </f:facet>   
        <f:facet name="input">
            <p:inputText value="#{item.addressline1}"/>
        </f:facet>
    </p:cellEditor>
</p:column>

Listing 6: Marking rows as editable

In Listing 6, the customer addressline1 column will be editable, and when the cell is selected, the field will change to a p:inputText component, as shown in Figure 11. This makes editing within DataTable components very easy.

primefaces-f11

Figure 11: Editable table cell

To persist the edit, you'll need to do something with the data after it is edited. To invoke an action after a cell has been edited, embed the <p:ajax> element inside the DataTable. The following <p:ajax> element can be embedded inside the customer/List.xhtml DataTable, and then the onCellEdit method of CustomerController will be invoked when a cell is edited.

<p:ajax event="cellEdit" listener="#{customerController.onCellEdit}" />   

The onCellEdit method can perform any action. The example in Listing 7 saves the contents of the edited table row to the database.

public void onCellEdit(CellEditEvent event) {  
    Object oldValue = event.getOldValue();  
    Object newValue = event.getNewValue();  
    if(!oldValue.equals(newValue)){
        // Save to the database
        DataTable table = (DataTable) event.getSource();
        Customer customer = (Customer) table.getRowData();
        ejbFacade.edit(customer);
        FacesContext.getCurrentInstance().addMessage(null, 
            new FacesMessage(FacesMessage.SEVERITY_INFO,"Successfully Updated", 
"Updated value to " + newValue));  
    }
}

Listing 7: Example of onCellEdit method

Rather than using single-cell editing, it is also possible to add a bit more control to editing functionality by creating a row editor. A row editor includes both submit and cancel functionality, and it enables editing for all the editable fields of a selected row. To add row editing to a DataTable, omit the editMode attribute entirely, and add the following column to either the front or the end of the table:

<p:column style="width:6%">  
    <p:rowEditor />  
</p:column>  

After adding the <p:rowEditor> element to the front of the customer/List.xhtml table, the New Enterprises row will resemble Figure 12.

primefaces-f12

Figure 12: Row editing capability

To persist the updates, add an event listener for row edits by embedding a <p:ajax> element into the DataTable, as shown below. In this case, two listeners have been added: one for when a row edit is submitted and another for when a row edit is canceled.

<p:ajax event="rowEdit" listener="#{customerController.onEdit}" />  
<p:ajax event="rowEditCancel" listener="#{customerController.onCancel}" />  

Using the tactics demonstrated in this section, you can develop sophisticated DataTable components for displaying and editing your enterprise data.

Providing Informative Messages

Since asynchronous editing is a valuable feature, it would also be nice to include some feedback for users, so they know whether their edits were successful. PrimeFaces makes it easy to include informative messaging. There are a couple different messaging solutions offered by PrimeFaces: growl and messages. In this article, we'll take a look at the messages component.

To make use of messages, add the <p:messages> element to all the relevant views that are enclosed within a form. For instance, Listing 8 shows the component added to the Customer List view.

...
<h:form id="CustomerListForm">
    <p:messages showDetail="true" autoUpdate="true" closable="true"/>
    <br/>
...

Listing 8: Using the <p:messages> element

As with the other components, there are several attributes that can be specified. To display a message within the component, add a FacesMessage to the current instance of the FacesContext. Listing 9 demonstrates how to add a message when a cell is edited within the view.

public void onCellEdit(CellEditEvent event) {  
            Object oldValue = event.getOldValue();  
            Object newValue = event.getNewValue();  
            if(!oldValue.equals(newValue)){
                // Save to the database
                DataTable table = (DataTable) event.getSource();
                Customer customer = (Customer) table.getRowData();
                ejbFacade.edit(customer);
                FacesContext.getCurrentInstance().addMessage(null, 
                    new FacesMessage(FacesMessage.SEVERITY_INFO,"Successfully
 Updated", 
                    "Updated value to " + newValue));  
            }
        }

Listing 9: Adding a message to a view

After editing a cell, the message should be displayed within the view, as shown in Figure 13.

primefaces-f13

Figure 13: PrimeFaces messages component

PrimeFaces 5

PrimeFaces 5 includes significant improvements, including new DataTable features such as frozen cells, draggable rows, and a column toggle that enables you to hide specified columns. Moreover, new components have been added to help you produce even more robust applications.

One of the most important new features is the addition of PrimeFaces mobile, which is a mobile component library based upon the jQuery Mobile framework. This feature provides the ability to include mobile views for your application pages, allowing the application to scale across devices of all sizes. The PrimeFaces mobile feature also includes performance-based features, such as lazy loading. The best part is that this feature allows mobile and desktop user interfaces to share business logic, making it easy to develop applications for the enterprise that have the ability to span all devices.

Conclusion

The JSF framework has proven to be an efficient development framework for solutions of all sizes. PrimeFaces can be included in JSF applications to significantly increase the options available for your applications. PrimeFaces includes components that provide increased functionality compared to the standard JSF component library. It also includes solutions to increase developer productivity, such as <p:ajax>, which makes it easy to wire components to business logic using less code. This article covered only a handful of features that PrimeFaces has to offer. For more, please visit primefaces.org.

See Also

About the Author

Josh Juneau (juneau001@gmail.com) works as an application developer, system analyst, and database administrator. He primarily develops using Java and other Java Virtual Machine (JVM) languages. Josh is a technical writer for Oracle Technology Network and Java Magazine. He coauthored The Definitive Guide to Jython and PL/SQL Recipes (both Apress 2010) and Java 7 Recipes (Apress 2011). He recently authored Java EE 7 Recipes and Introducing Java EE 7 (Apress 2013). Josh is currently authoring the upcoming Apress title Java 8 Recipes, which will be published later this year.

Join the Conversation

Join the Java community conversation on Facebook, Twitter, and the Oracle Java Blog!