Developing Applications Using ICEfaces

ICEfaces® is an open source AJAX framework that enables you to include AJAX-enabled components in your applications without writing any JavaScript code. In this tutorial, you will create an application for viewing and modifying the contents of a Customer database table. You will learn how to:

  • Add JPA and ICEfaces facets to a Web project
  • Open a DB connection
  • Reverse engineer a database table to generate entities
  • Add a managed bean
  • Create an XHTML page for ICEfaces
  • Bind a Data Table Component to the Database
  • Add an ICEfaces pagination and row selector components

Duration Time: 45 Minutes

Start Tutorial Now

Don't have MyEclipse? Download Now

1. Create a Web Project

To see the entire project used in this tutorial, download ICEFacesProject.zip.

  1. Click the drop-down arrow , and select Web Project from the menu.
  2. Type ICEFacesProject in the Project name field, accept the default options, and click Finish.

    Note: This tutorial uses the default JavaEE 6 version; however, JavaEE 7 is an available option when creating new projects.

    Creating a Web project

2. Connect to MyEclipse Derby Database

You  cannot add  JPA facets to your project until you set up a database connection. When adding the JPA facet, you are required to select the connection to use.

  1. Click , and select MyEclipse Database Explorer.
  2. In the DB Browser, select the MyEclipse Derby connection, and click . This starts the embedded MyEclipse Derby server and gives you instant access to the tables in the database.

    Opening the database connection

The table you will work with is the  CUSTOMER table.

Sample tables

3. Add the JPA Facet

Now that the DB Connection is set up, you can add JPA facets to the project so it can use tables and information from the DB Connection.

  1. Switch back to the MyEclipse Java Enterprise perspective, right-click the project, and select MyEclipse>Project Facets>Install JPA Facet.
  2. Accept the defaults, and click Next.

    Configuring JPA capabilities
  3. Select a platform from the Platform drop-down. If the JPA implementation type defaults to a User Library, select the library corresponding to the selected platform. If no library is listed, click to download the appropriate library.

    Selecting a library
  4. Select MyEclipse Derby in the Connection field, select the Add driver library to build path and Override default schema from connection checkboxes, and choose CLASSICCARS from the Schema drop-down. Click Finish.
    Completing the JPA facet configuration

Now the project has a fully configured JPA facet added to it, which includes JPA  configuration information, DB Connection information, and all necessary JDBC and JPA  libraries added to the project's build path. All build-path additions are  prepared to be deployed and run on an app  server.

Project structure

4. Reverse Engineer a Database Table

  1. Right-click the project, and select MyEclipse>Generate Entities & DAOs.

    Note:
    You have the option to use MyEclipse reverse-engineering tools or DALI entity generators. Make a selection, click OK, and complete the wizard. This tutorial uses the MyEclipse reverse-engineering tools.

    Reverse-engineering tool selection
  2. Select the CUSTOMER table, click Add, and click Next.

    Specifying the CUSTOMER table to be reverse engineered
  3. In the Java Package field, type com.myeclipseide.jpa. Select the following checkboxes:

    Entity Bean Generation: Tells MyEclipse to generate plain Java classes that are annotated to be used as JPA entities 

    Update persistence.xml: Similar to Hibernate;you can list all the JPA entities you are using in the JPA configuration file.

    Java Data Access Generation: Tells MyEclipse to generate DAO utility classes for you that allow you to save/find/update/delete the entities from the database right away. This code wraps the JPA entity manager and makes using the entities and the DB very easy. 

    Generate precise findBy methods:
     Tells MyEclipse to generate findBy XXX methods where XXX pertains to each property on the entities that are reversed. This allows easy access to entities from the DB using any property as a means of finding them.

    Generate Java interfaces: Selecting this option creates an interface class with a corresponding DAO implementation class. Deselecting this option generates only the DAO implementation class without a separate class defining the interface.


    Setting up reverse engineering
  4. Click Finish.You can view the resources MyEclipse generated by expanding the com.myeclipseide.jpa package in the Explorer view.

    Note: To remove the error in customer.java, delete references to the Payment object, as the ICEfaces tutorial doesn't use it and code for it was not generated.

    Generated classes

The generated entities are described as follows:

  • EntityManagerHelper: When using straight JPA, developers need to make use of the EntityManager class. This generated helper class makes using EntityManager a much easier process by providing static methods to access the manager as well as the most common operations readily available to call.
  • ICustomerDAO: The class that defines the interface for the corresponding DAO implementation class.
  • Customer: This class is the JPA Entity (POJO) that represents the DB table PRODUCTLINE. This POJO contains the fields of the CUSTOMER table and represents one row in the DB.
  • CustomerDAO: This class wraps the EntityManagerHelper to give us easy-to-use methods, specifically for adding/finding/updating and deleting products from the DB.

Note: After reverse-engineering is finished, you can open the  Persistence perspective to use some of the persistence  and data source tools to analyze data in your DB and project.

5. Add the ICEfaces Facet

The Web project needs to be configured for JSF and ICEfaces. When you add the ICEfaces facet, the JSF facet is automatically included.

  1. Right-click the project, and select MyEclipse>Project Facets>Install ICEfaces Facet. Accept the default options on the first page, and click Next.
  2. Select Mojarra 2.1.22 from the JSF Implementation drop-down, and click Next.

    Selecting JSF implementation
  3. Deselect the Mobi ICEfaces library, and click Finish.

    Configuring project libraries

6. Add a ManagedBean

With JSF 2.0 and above, managed beans can be configured with annotations leaving the faces-config.xml file untouched. Instead of modifying the managed bean in the config file, this step can be further simplified using an @ManagedBean (name = "sessionBean") annotation definition in the SessionBean class definition. During runtime, the class is scanned and the annotation definition tells the JSF runtime that the SessionBean class is the managed bean.

For this tutorial, the managed bean is configured using the configuration editor.

  1. In the project, expand the WebRoot>WEB-INF folder, and open faces-config.xml.
  2. Click the ManagedBean tab at the bottom of the editor, and click Add.
  3. Select Create a new Java class, and click Next.
  4. In the Package field, type com.myeclipseide.ui, type SessionBean in the Name field, and click Next.

    Creating the managed bean
  5. Select session from the Scope drop-down, and click Finish. The ManagedBean appears in the config file. Press CTRL+S to save.

    Managed bean in faces-config.xml
  6. Open the SessionBean.java file and replace the default code with the following, and save the file.

    Note:
    Some imports are added here, but are not used until a later step.
    package com.myeclipseide.ui;
    import java.util.ArrayList;
    import java.util.Collection;
    import javax.faces.event.ActionEvent;
    import com.icesoft.faces.component.ext.RowSelectorEvent;
    import com.myeclipseide.jpa.Customer;
    import com.myeclipseide.jpa.CustomerDAO;
    import com.myeclipseide.jpa.EntityManagerHelper;

    public class SessionBean {
    private CustomerDAO customerDAO = new CustomerDAO();
    /**
    * @return the customerDAO
    */
    public CustomerDAO getCustomerDAO() {
    return customerDAO;
    }

    /**
    * @param customerDAO the customerDAO to set
    */
    public void setCustomerDAO(CustomerDAO customerDAO) {
    this.customerDAO = customerDAO;
    }
    }

The SessionBean class requires a reference to the CustomerDAO class, so changes made from the view can be persisted to the database when necessary. When the SessionBean class is instantiated, it will have a reference to CustomerDAO.

You now have a session scope managed bean (sessionBean) that is accessible through  JSF mechanisms. When each new session is created and a user views a page, the component bindings on the page cause a new bean to be instantiated and user interaction with the page is stored in the session-specific  backing bean.

7. Create an XHTML Page for ICEfaces Components and  Bindings

  1. Right-click WebRoot, and select New >XHTML (Advanced Templates).
  2. Select ICEfaces 3 Page(.xhtml) from the Template to use drop-down, and click Finish.

    Creating an XHTML page

7.1 Bind a Data Table Component to the Database

The goal is to view and modify the contents of the Customer table in the database. Begin by adding an ice:dataTable component to the .xhtml page.

  1. In the palette, open the ICEfaces ICE Components folder, click the dataTable tool, and click the Design view page after the welcome text inside the h:form.

    Adding the dataTable component
  2. Open SessionBean.java, add the following code before the final bracket, and save the file.
    public SessionBean(){
    customerList.addAll((Collection<? extends Customer>) customerDAO.findAll());
    }

    public ArrayList<Customer> getCustomerList() {
    return customerList;
    }
    public void setCustomerList(ArrayList<Customer> customerList) {
    this.customerList = customerList;
    }
    This creates an ArrayList named  customerList in the sessionBean and adds a constructor to initialize the ArrayList with the findAll()  method from CustomerDAO. When the session starts, the constructor populates this list with values from  the database.
  3. Return to MyXhtml.xhtml, select the dataTable, and type #{sessionBean.customerList} in the value field on the Quick Edit tab of the Properties view.
  4. Type customer in the var property.

    Binding the dataTable component to the database
  5. Select the "column1" header in the Design view, and in the Properties view, change the value to First Name. Do the same with "column2," changing the value to Last Name.
  6. Click the outputText component tool in the palette, click the first column, and type #{customer.contactfirstname} in the value property.
  7. Click the outputText component tool in the palette, click the second column, and type #{customer.contactlastname} in the value property. Press CTRL+S to save the file.

    Completed table

In these bindings, customer refers to the var attribute of the dataTable. Each row will have a reference  to each object in the ArrayList bound to the dataTable, which is a Customer object. If you open the Customer.java class, you will see the properties available for binding to the user interface.

8. Deploy and Test the Application

If the Servers view is not open, select Window>Show View>Servers.

  1. In the Servers view, right-click MyEclipse Derby, and select Start, if it is not already running.
  2. Right-click MyEclipse Tomcat, and select Add/Remove Deployments.
  3. Select the ICEFacesProject in the Available column, click Add, and click Finish.
  4. In the Servers view, right-click MyEclipseTomcat, and select Start, if it isn't already running.
  5. Click the on the toolbar, and type http://localhost:8080/ICEFacesProject/MyXhtml.faces in the URL field. You should see a table populated with all the customers in the database.

    Running the application

9. Add ICEfaces Pagination and RowSelector Components

The dataTable list does not fit in the browser window, so it would be useful to break the list into pages. This can be done with the dataPaginator component.

  1. Back in MyXhtml.xhtml, click the dataPaginator tool in the palette, and place it in the form above the dataTable component.

    dataPaginator added to the form
  2. In the Properties view, type customerDataTable in the for field, select True from the paginator drop-down, and type 3 in the fastStep field. 

    The only required attribute for the dataPaginator is the for attribute, which requires the id of the dataTable the paginator will traverse. By setting the fastStep property, the dataPaginator will move ahead three pages with the fastStep button. Setting paginator property to "true" displays page numbers in the dataPaginator.

    Paginator properties
  3. Select the dataTable in the Design view, and in the Properties view, enter an id of customerDataTable to bind the dataPaginator to the dataTable. Click Attributes, and set the JSF>rows attribute to 5 so each page of data will display five rows. Save the file.
  4. Open or refresh the page in the MyEclipse Web Browser to see the change.

    Customer list with paginatorNext, you will add a rowSelector component to the dataTable so you can select a specific row in the dataTable for modification.
  5. In the Design view of MyXhtml.xhtml, right-click the dataTable, and select DataTable, Add RowSelector.

    The RowSelector requires a value binding to a boolean in a bean that tracks whether or not the row has been selected. Every row represents a Customer, and you need to know if a Customer has been selected. However, different users (sessions) could be selecting different rows, so Customer object needs to be wrapped in a CustomerBean class containing session-specific information on each Customer.
  6. Right-click the com.myeclipseide.ui package, and select New>Class.
  7. Type CustomerBean in the Name field, and click Finish.
  8. In CustomerBean.java, replace the default code with the following, and save the file.
    package com.myeclipseide.ui;
    import com.myeclipseide.jpa.Customer;
    public class CustomerBean {
    private Customer customer;
    private boolean selected = false;
    public CustomerBean (Customer customer){
    this.customer = customer;
    }

    public Customer getCustomer() {
    return customer;
    }

    public void setCustomer(Customer customer) {
    this.customer = customer;
    }

    public boolean isSelected() {
    return selected;
    }

    public void setSelected(boolean selected) { this.selected = selected;
    }
    }
    This code creates a Customer member variable and a constructor taking a Customer object as a parameter to initialize the Customer variable. It also adds the "selected" boolean with getter and setters - this boolean is bound to the rowSelector component.
  9. Return to MyXhtml.xhtml, select the rowSelector component, and enter #{customerbean.selected} as the value property to add the binding to the rowSelector component.

    The dataTable var attribute references now refer to CustomerBeans instead of Customers, soyou should change the var attribute from "customer" to "customerbean." If you change the var attribute, you also have to make this change to all the value bindingsusing "customer" inside the dataTable. For instance, when accessing the Customer properties,the binding should change from "customer.contactlastname" to "customerbean.customer.contactlastname."

    Finally, you will make another change that is necessary as multiple users visit the application and create their own session beans. You need to keep a single List of Customers that all users can access so when they create lists of CustomerBean objects, they are wrapping the same Customer objects.
  10. Open SessionBean.java and replace all instances of <Customer> to <CustomerBean>. You will replace public SessionBean later, so for now, ignore the error. 
  11. Right-click the com.myeclipseide.ui package, and select New>Class.
  12. Type CustomerList in the Name field, and click Finish.
  13. In CustomerList.java, replace the default code with the following, and save the file.
    package com.myeclipseide.ui;

    import java.util.ArrayList;
    import com.myeclipseide.jpa.Customer;

    public class CustomerList {
    protected static ArrayList<Customer> customerList;
    public static ArrayList<Customer> getCustomerList() {
    return customerList;
    }

    public static void setCustomerList(ArrayList<Customer> customerList) {
    CustomerList.customerList = customerList;
    }
    }
  14. CustomerList contains a static ArrayList of Customer objects initialized in the SessionBean. Open SessionBean.java, and add a static boolean  "initialized" and modify the code in the constructor so the first session  started in the application creates the static List of Customers that will  then be used to initialize all the CustomerBean ArrayLists created in future  sessions.
    private static boolean initialized = false;
    private static final Object lock = new Object();

    public SessionBean(){
    synchronized (lock){
    if(!initialized){
    CustomerList.customerList = new ArrayList<Customer>(customerDAO.findAll());
    initialized = true;
    }
    }
    for(int i=0;i<CustomerList.customerList.size();i++){
    customerList.add(new CustomerBean(CustomerList.customerList.get(i)));
    }
    }

Now the application is ready to modify the underlying customer data and save  it to the database. With the rowSelector component, you can select a customer  from the dataTable and view it in a separate table where changes can be made  to the customer.

10. Updating the Database from the Data Table

To update the database, you will modify the selected customer in a separate table outside the dataTable.

  1. In MyXhtml.xhtml, click the Form tool on the palette, and click the Design view after the form containing the dataTable. The forms should not be nested.
  2. Click the panelGrid tool on the palette, and click inside the new form. The panel grid is placed into its own form so interaction with the dataTable does not cause the panel grid bindings to be submitted.
  3. Select the panel grid, enter 4 in the columns property, and set the JSF>rendered attribute to #{sessionBean.selectedView}. This panel grid renders only when the RowSelector has been used to select a CustomerBean.
  4. Click the inputText tool on the palette, and click the "item1" cell. Enter a value property of #{sessionBean.selectedCustomerBean.tempcontactfirstname}.
  5. Add another inputText component in the "item1" column, and enter a value property of #{sessionBean.selectedCustomerBean.tempcontactlastname}.
  6. Click the commandButton tool on the panel, and click the "item1" cell. A command button is added in a new column. Enter a value property of Commit.
  7. In the JSF>actionListener property, enter a value of #{sessionBean.commit}.
  8. Add another command button in the "item1" cell with a value of Cancel, and an actionListener value of #{sessionBean.cancel}. Delete the items in the second row of the panel grid.

    Completed panel grid
  9. Select the rowSelector component, and enter #{sessionBean.rowSelected} as the JSF>selectionListener attribute to render the table. Save the file.
  10. The previous changes to the .xhtml page require the following additions to the beans:

    CustomerBean:

    private String tempcontactfirstname;
    private String tempcontactlastname;

    public CustomerBean (Customer customer){
    this.customer = customer;
    tempcontactfirstname = customer.getContactfirstname();
    tempcontactlastname = customer.getContactlastname();
    }

    public String getTempcontactfirstname() {
    return tempcontactfirstname;
    }

    public void setTempcontactfirstname(String tempcontactfirstname) {
    this.tempcontactfirstname = tempcontactfirstname;
    }

    public String getTempcontactlastname() {
    return tempcontactlastname;
    }

    public void setTempcontactlastname(String tempcontactlastname) {
    this.tempcontactlastname = tempcontactlastname;
    }

    SessionBean:

    private CustomerBean selectedCustomerBean;
    private boolean selectedView = false;

    public void rowSelected (RowSelectorEvent e){
    selectedCustomerBean = (CustomerBean)customerList.get(e.getRow());
    selectedCustomerBean.setTempcontactfirstname(selectedCustomerBean.getCustomer().getContactfirstname());
    selectedCustomerBean.setTempcontactlastname(selectedCustomerBean.getCustomer().getContactlastname());
    selectedView = true;
    }

    public CustomerBean getSelectedCustomerBean() {
    return selectedCustomerBean;
    }

    public void setSelectedCustomerBean(CustomerBean selectedCustomerBean) {
    this.selectedCustomerBean = selectedCustomerBean;
    }

    public boolean isSelectedView() {
    return selectedView;
    }

    public void setSelectedView(boolean selectedView) {
    this.selectedView = selectedView;
    }

    public void commit(ActionEvent e){
    selectedCustomerBean.getCustomer().setContactfirstname(selectedCustomerBean.getTempcontactfirstname());
    selectedCustomerBean.getCustomer().setContactlastname(selectedCustomerBean.getTempcontactlastname());
    EntityManagerHelper.beginTransaction();
    customerDAO.update(selectedCustomerBean.getCustomer());
    EntityManagerHelper.commit();
    selectedView = !selectedView;
    }

    public void cancel(ActionEvent e){
    selectedView = !selectedView;
    }

CustomerBean now contains two member variables, tempContactfirstname and  tempContactlastname, bound to the inputText components in the panel grid. You  need temporary Strings in these fields as you do not want to change the underlying  data until the user has clicked the Commit button.

SessionBean has two new member variables. First, you have the selectedCustomerBean, which is the CustomerBean selected with the RowSelector component. It is retrieved via the rowSelected method that is bound to the RowSelector's selectionListener. The rowSelected method also sets the other new member variable, the selectView boolean, to true. This boolean is bound to the rendered attribute of the new panel grid so users can see the panel grid and make changes to the customer when a selection has been made.

SessionBean also contains two methods bound to the command button actionListeners. The "Commit" button persists changes to the CustomerBean's underlying customer object and the "Cancel" button causes the customer update panel grid not to render.

If you now deploy the application and open an external browser window as well as the browser built in to MyEclipse, you see that the application maintains the state of two different user's (sessions) interaction with the application. Committing changes to a customer in either view persists the underlying data to the database. You can verify this  by switching to the MyEclipse Database Explorer perspective and viewing the contents  of the CUSTOMER table.

Updating a customer record