MyEclipse Logo

MyEclipse ICEfaces Tutorial


ICEfaces® is a powerful open source Ajax framework that enables Java EE developers to easily create and deploy rich Internet applications (RIA) in pure Java. ICEfaces leverages the entire standards-based Java EE ecosystem of tools and execution environments. Rich enterprise application features are developed in pure Java, and in a pure thin-client model. ICEfaces applications are JavaServer Faces (JSF) applications, so Java EE application development skills apply directly and Java developers are isolated from doing any JavaScript related development.

Table of Contents

  1. Create a Web Project and Connect it to the Database
  2. Add JSF/ICEfaces Capabilities to the Web Project
  3. Bind a Data Table Component to the Database
  4. Adding ICEfaces Components to the Data Table
  5. Updating the Database from the Data Table

1. Create a Web Project and Connect it to the Database

ICEfaces will provide AJAX enabled components to your application without writing any Javascript. Before we create a page with ICEfaces components, we will create a Web Project and Connect it to the Database.

For this step we will follow the "Learn to use the Java Persistence Tools (JPA)" Tutorial using the built-in MyEclipse Derby database. You can access this tutorial from MyEclipse by selecting Help -> Welcome -> Tutorials -> Learn to use the Java Persistence Tools (JPA). Please make note of these modifications to the tutorial:

For the "Setting up your Project" step we will be creating a web project. File -> New -> Web Project, Select Java EE 5.0.

From "Setting up DB Connection" onwards We will use the CLASSICCARS CUSTOMER table (instead of the PRODUCTLINE table).

You must delete references to the Payment object in Customer.java after Reverse Engineering.

You can stop after number 5, Reverse Engineering. Close the Welcome window in MyEclipse and return to MyEclipse Java Enterprise Perspective.

2. Add JSF/ICEfaces Capabilities to the Web Project

Our web project needs to be configured for JSF and ICEfaces. MyEclipse can do this automatically. Highlight the project, either right click on the project and choose MyEclipse or choose the MyEclipse option from the menu and select "Add JSF Capabilities...", accepting the default options. Repeat the same steps and choose "Add ICEfaces Capabilities..." accepting the default options. The appropriate libararies and web.xml entries have been added to your project.

Now we will create a package to contain beans we will bind to our ICEfaces components. Our package name is org.icefaces.ui because these beans are used by the user interface, or view.

Lets add a class to this package called SessionBean. This class will be a session scope JSF managed bean and will encapsulate the user's interaction with the view during their session. From the WebRoot folder of the application, go to the WEB-INF folder and open faces-config.xml. Choose the "Source" tab, beside the "Design" tab at the bottom of the page when viewing faces-config.xml. Right click on the page and choose JSF -> Add ManagedBean. Fill out the dialog as follows, the source code will be generated for you:

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

package org.icefaces.ui;

import org.icefaces.jpa.CustomerDAO;

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;
}

}

We now have a session scope managed bean (SessionBean) that will be made accessible to us through JSF mechanisms. When each new session is created and a user views a page, the component bindings on the page will cause a new bean to be instantiated and user interaction with the page will be stored in the session specific backing bean. Lets create the page that will contain the ICEfaces components and bindings to the backing bean. Right Click WebRoot -> New -> JSP (Advanced Templates). Choose ICEfaces JSPX page template (.jspx) and add an "x" to the end of the file name, press the Finish button.

You will now see the Design view for our page. By default the page contains an ice:outputText component thanking you for using ICEfaces, an ice:form and an ice:messages component (useful for debugging, this component will output errors). There is also a link in the tag referring to the ICEfaces xp.css stylesheet to provide default styles to the components.


3. Bind a Data Table Component to the Database

Our goal is to view and modify the contents of the Customer table in the database. We will start by adding an ice:dataTable component to our .jspx page.

Click on Palette in Design view, select the ICEfaces folder and scroll down to Data Table. Drag the Data Table into the Design view, before the ice:messages component and inside the ice:form.

Now bind the ice:dataTable "value" attribute to data in the bean. Create an ArrayList named customerList in the SessionBean. Add a constructor to initialize the ArrayList with the findAll() method from CustomerDAO. When the session starts, the constructor will populate this list with values from the database.

private ArrayList<CustomerBean> customerList = new ArrayList<CustomerBean>();

public SessionBean(){
customerList.addAll(customerDAO.findAll());
}

public ArrayList<CustomerBean> getCustomerList() {
return customerList;
}

public void setCustomerList(ArrayList<CustomerBean> customerList) {
this.customerList = customerList;
}

Return to MyJsp.jspx and create the binding. Select the Properties tab, go to "value" and add the binding #{sessionbean.customerList}. The Data Table "var" attribute is a String that references each object in the List, we will use "customer" which makes sense because each object in the List is an instance of the Customer class.


Now that we have the data binding, lets bind some specific Customer information to the view.

We are going to output the first and last names of every Customer in our customer list. Double click on the "column1" header in Design view and change the value to "First Name". Do the same with "column2" changing the value to "Last Name". Drag an Output Text component from the Palette into the first column, repeat for the second column. Double click on the first column's Output Text component and enter a value of #{customer.contactfirstname}, repeat with the second column entering a value of #{customer.contactlastname}. The customer in these bindings refers to the "var" attribute of the Data Table. Each row will have a reference to each object in our ArrayList bound to the Data Table, which is a Customer object. If you open the Customer.java class in our source code, you will see the properties available for binding to the user interface.

Time to run the application. Select the Servers tab and you should see references to MyEclipse Derby and MyEclipse Tomcat that come with your installation of MyEclipse. Right click and choose Run Server on MyEclipse Derby, if it is not already running. Right click and choose Manage Deployments on MyEclipse Tomcat, choose Add, the New Deployment screen will pop up, select the project from the dropdown menu and leave the Deploy type at Exploded Archive, hit Finish, hit OK on the Server Deployments Dialog. Right click MyEclipseTomcat in the Servers tab and select Run Server. Open the MyEclipse Web Browser from the Menu Bar and type in the url http://localhost:8080/myeclipse-tutorial3/MyJsp.iface. You should see a table populated with all the Customers in the database.


4. Adding ICEfaces Components to the Data Table

The Data Table list does not fit in the browser window, so it would be a good idea to add a Data Paginator component to break up the viewable Customers. From the Pallette, under ICEfaces, drag a Data Paginator into the Design view before the Data Table and inside the Form. The only required attribute for the Data Paginator is the "For" attribute which requires the id of the Data Table the Data Paginator will traverse. Under "For" enter "customerDataTable", under "fastStep" enter "3" so that the Data Paginator will move ahead three pages with the fastStep button and finally, set "paginator" to "true" so we will see page numbers in the Data Paginator. Now highlight the Data Table in Design View and enter an ID of "customerDataTable" to bind the Data Paginator to the Data Table. In the Data Table properties tab, click on Attributes and set "rows" to "5" so each page of data will show 5 rows with the Data Paginator.

We will add a RowSelector component to our Data Table so we can select a specific row in the Data Table for modification. In Design view, highlight the Data Table, right click, DataTable, Add RowSelector. The RowSelector will require a value binding to a boolean in a bean that will keep track of whether or not the row has been selected. Every row represents a Customer and we need to know if a Customer has been selected. However, different users (sessions) may be selecting different rows, so we will need to wrap the Customer object in a CustomerBean class that will contain session specific information on each Customer.

In the org.icefaces.ui package, right click, New, Class and input the name "CustomerBean", hit Finish. In CustomerBean, create a Customer member variable and a constructor taking a Customer object as a parameter to initialize the Customer variable. Now add the "selected" boolean with getter and setters - this boolean will be bound to the RowSelector component.

package org.icefaces.ui;

import org.icefaces.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;
}
}

Finally, in our SessionBean constructor where we initialize our customerList, we will now wrap each Customer in a CustomerBean so that each session will keep track of it's own user interface interaction with the Customer objects.

public SessionBean(){

List<Customer> tempList = customerDAO.findAll();

for(int i=0; i<tempList.size(); i++){
customerList.add(new CustomerBean(tempList.get(i)));
}

}

Return to MyJsp.jspx and add the binding to your RowSelector component.

value="#{customerbean.selected}"

The Data Table "var" attribute references now refer to CustomerBeans instead of Customers, so you should change the var attribute String from "customer" to "customerbean". If you change the var attribute, you will also have to make this change to all the value bindings using "customer" inside the Data Table. For instance, when accessing the Customer properties, the binding will change from "customer.contactlastname" to "customerbean.customer.contactlastname".

We will make another change that is necessary as multiple users visit our application and create their own session beans. We will keep a single List of Customers that all users can access so that when they create Lists of CustomerBean objects they will be wrapping the same Customer objects.

In our org.icefaces.ui package New, Class and input the name "CustomerList", hit Finish.

package org.icefaces.ui;

import java.util.ArrayList;

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;
}

}

CustomerList contains a static ArrayList of Customer objects that we will initialize in the SessionBean. In the SessionBean, add a static boolean "initialized" and modify the code in the constructor so that the first session started in the application will create 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 our application is ready to modify the underlying Customer data and save it to the database. With the RowSelector component, we will select a Customer from the Data Table and view it in a separate table where changes will be made to the Customer.

5. Updating the Database from the Data Table

We will modify the selected Customer in a separate table outside the Data Table. Drag a Panel Grid component into the Design view after the Data Table and before the Messages component, inside the Form. We are going to put this Panel Grid into it's own Form so interaction with the Data Table will not cause the Panel Grid bindings to be submitted. Add the following before the Panel Grid:

</ice:form><ice:form>

In our Panel Grid, set the columns attribute to "4" and the rendered attribute to #{sessionbean.selectedView}. This Panel Grid will only render when the RowSelector has been used to select a CustomerBean. Now add the following 4 columns to the Panel Grid:

<ice:inputText value="#{sessionbean.selectedCustomerBean.tempcontactfirstname}"></ice:inputText>
<ice:inputText value="#{sessionbean.selectedCustomerBean.tempcontactlastname}"></ice:inputText>
<ice:commandButton value="Commit" actionListener="#{sessionbean.commit}"></ice:commandButton>
<ice:commandButton value="Cancel" actionListener="#{sessionbean.cancel}"></ice:commandButton>

The RowSelector component will require the following selectionListener attribute to render the table:

selectionListener="#{sessionbean.rowSelected}"

These changes to our .jspx page will require the following additions to our 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 Input Text components in our Panel Grid. We need temporary Strings in these fields as we do not want to change the underlying data until the user has pressed the Commit button.

SessionBean has two new member variables. First we 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 our other new member variable, the selectView boolean, to true. This boolean is bound to the rendered attribute of our new Panel Grid so we 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 will persist changes to the CustomerBean's underlying Customer object and the "Cancel" button will cause 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 will see that the application will maintain the state of two different user's (sessions) interaction with the application. Committing changes to a Customer in either view will persist to 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.