What is ICEFaces?
ICEfaces is an integrated AJAX Java application framework that enables Java EE AJAX application developers to easily create and deploy thin-client Rich Internet applications (RIA) in pure Java. ICEfaces is a fully featured product that enterprise developers can use to develop new or existing Java EE AJAX applications at no cost.
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. There are no Applets or proprietary browser plug-ins required. 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.
ICEfaces 1.8: Next Generation Enterprise Web Development
ICEfaces is the technology leader in the integration of AJAX with the JEE stack. Its vendor, ICEsoft, offers a wide support for application servers, portal servers, and important open source frameworks. So, you do not have to bother yourself with the integration aspects of your project. You can focus on the implementation of business logic and its presentation in the web browser instead.
If you plan a rock-solid Web 2.0 implementation based on the JSF standard, ICEfaces is an ideal solution. Important enhancements of the JSF 2.0 standard are already available in ICEfaces 1.8. So, you can expect minimal porting efforts. icefaces 1.8 technologies such as skinning, multimedia, and AJAX Push already deliver the standards of tomorrow and ease the development of collaborative web applications. icefaces 1.8 can even be mixed with modern RIA concepts based on Adobe Flex. A community of almost 90,000 developers (at the end of 2009) proves the quality and potential of the icefaces 1.8 implementation.
This book is an introduction to the icefaces 1.8 framework for enterprise developers with JSF experience. It describes how you can use icefaces 1.8 components to build Web 2.0 applications with a desktop-like character.
The book examples will explain to you how ICEfaces 1.8 helps integrating AJAX into a JEE stack (using AJAX Push, JSF, Facelets, Spring, and JPA/Hibernate) without using a line of JavaScript code. The book has a special focus on the Facelets technology that is now a part of the JSF 2.0 specification. This will help you to write your own components for a better reuse and maintenance.
By the end of the book, you will have a solid understanding of how to build modern and ergonomic web interfaces that fully integrate with the modern Java Enterprise stacks. You will be able to design and implement reusable and maintainable presentation components that allow creating customizable, skinnable, and multilingual web applications.
What This Book Covers
This book focuses on the implementation of desktop-like web applications that generate a high user acceptance. Each chapter describes a different aspect of how ICEfaces 1.8 can be used to achieve this.
Chapter 1 gives a short introduction of modern JEE web development. It shows why we use AJAX and JSF today, and why ICEfaces 1.8 is an ideal framework to use.
Chapter 2 helps you to set up tools and frameworks that are used to create and execute the sample code. We will have a look at a Windows XP environment using the Sun Microsystems JDK, the Eclipse IDE, the Maven 2 Build System, the Jetty web container, and the MySQL Database system. There is a special focus on the installation and the use of the ICEfaces 1.8 plugin for Eclipse.
Chapter 3 takes a look at what a desktop-like presentation means to modern web applications. We will have a look at the design principles and start with a common page layout based on the Facelets templating.
Chapter 4 presents the ICEfaces 1.8 components that help us to implement an intuitive navigation. The layout ideas from the previous chapter are further developed using the ICEfaces 1.8 components.
Chapter 5 shows how your web application provides feedback to the user. We will have a deeper look at the special Facelets components that deliver similar functionality to that which a desktop developer would use in his/her applications. Additionally, we will have a look at the ICEfaces 1.8 components that deliver a desktop-like behavior so that the user gets fast results with minimal effort.
Chapter 6 discusses data presentation components. We will focus on dynamic data tables that are fed by the database, and offer sortable and resizable columns. The second part of the chapter describes how to integrate Google Maps, videos, and Flash animations into
your web application.
Chapter 7 describes the partial submit concept that ICEfaces 1.8 offers to update forms on the fl y. We also take a look at dialog-based validation and how advanced form elements, such as calendars and rich text editors, can be used.
Chapter 8 offers a model on how to implement the idea of user settings with the help of ICEfaces 1.8. We will take a deeper look at the language and skin management.
Chapter 9 takes a deeper look at the implementation details of Facelets components that were used in the previous chapters. We will discuss some fundamental design principles that help to create reusable and maintainable components without ever writing JSF custom components from scratch.
Components for Data Presentation and Multimedia
This chapter will discuss components that are primarily used to present data in different formats. We will start with the classic data table and tree components surely, the most used components in enterprise programming. Next, we will take a look at the charts and maps that are specialized in graphical data presentation. Multimedia presentations are on the way to becoming the next important standard. So, we will also take a look at video presentation components.
Data table
The ICEfaces 1.8 data table follows the implementation of the JSF standard data table. It is primarily enhanced with skinning and security features. It also has some additional components that make its use more comfortable. We will have a look at two variants of the ICEfaces 1.8 data table in this chapter. Both implementations use the same set of data. First, we will take a look at the
static variant and discuss important JSF features. Next, we will take a look at a dynamic implementation that is offered by the <icefusion:table> tag.
The static table example can be found in the ICEcube menu at Presentation | Data Table and looks like this:
In ICEfaces 1.8, a data table is defined by an <ice:dataTable> tag, some <ice:column> tags, and a list of objects. The implementation of the ICEcube example page can be found at /src/main/webapp/icecube/presentation/dataTable.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ice="http://www.icesoft.com/icefaces/component" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jstl/core" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:icefusion= "http://icefusion.googlecode.com/icefusion"> <body> <ui:composition template=”#{iceFusionConsts.templatePage}”> <ui:define name=»title»> #{icecube['application.menu.presentation.dataTable']} </ui:define> <ui:define name=»content»> #{icecube['application.menu.presentation.dataTable.text']} <ice:form> <ice:panelGrid> <b><ice:dataTable id="table" var="tableRows"</b> value="#{dataTable.rowsList}" rows="3" resizable="true"> <ice:column> <f:facet name="header"> <ice:outputText value="#{icecube[ 'application.menu.presentation. dataTable.attribute.firstname']}"/> </f:facet> <ice:outputText <b>value="#{tableRows.firstname}"/></b> </ice:column> </ice:dataTable> </ice:panelGrid> </ice:form> </ui:define> </ui:composition> </body> </html>
The list of objects that is delivered by the backing bean is referenced in the value attribute of the dataTable. The dataTable iterates over the value list and sets the var attribute for each member. The column tags define how the data has to be presented for each member. You may have recognized the bigger lines between the columns in the screenshot. These are a result of the resizable attribute in the dataTable tag. If you click on these and move the mouse, the size of the left column is changed. Normally, you have to start with the outer right columns to get a useful result. In the backing bean, we define a list of Java authors with their names, blog addresses, and a fl ag if JSF is their main business (/src/main/java/com/googlecode/icecube/presentation/DataTable.java):
package com.googlecode.icecube.presentation; import com.googlecode.icefusion.ui.commons.BackingBeanForm; import com.googlecode.icefusion.ui.commons.form.ITable; import com.googlecode.icefusion.ui.commons.form .ITableRowSortable; public class DataTable extends BackingBeanForm implements ITable { private ArrayList<DataTableRow4JavaAuthors> authors = new ArrayList<DataTableRow4JavaAuthors>(); protected void init() { authors.clear(); authors.add(new DataTableRow4JavaAuthors( "Rod","Johnson", "http://blog.springsource.com/author/rodj/",false)); authors.add(new DataTableRow4JavaAuthors( "Matt","Raible", "http://raibledesigns.com/",false)); this.initialized = true; } public List<ITableRowSortable> getRowsList() { if (!this.initialized) { init(); } return this.getAuthors(); }
The list of object construct behind the value attribute allows us to use well-known components from the Java collections, such as List or Map. Just as they can handle any kind of object, the dataTable tag can also do this. In combination with the JSF Expression Language (EL) and its internal refl ection, we are able to implement highly reusable presentation components for different business contexts. The EL lets you reference an attribute by its name, which is independent from its type. So, it is possible to use different objects that use the same name for a certain attribute in the same context without any adaptation in the XHTML or the backing bean. This is independent from the list type or the attribute type you use with such an attribute name.
In our example, we have a DataTableRow4JavaAuthors class that allows us to define the necessary attributes that we want to present in the columns. The class is a simple POJO that defines attributes with getters and setters.
Pagination
Normally, the dataTable lists have so many objects that it is not useful to present these all at once in the web browser. So, we need a dataTable extension that allows limiting the number of objects to render for a single page. For this, we use the <ice:dataPaginator> tag. It also offers navigation inside the object list. (See the navigation bar in the screenshot above.) The ICEcube example defines the navigation like this (/src/main/webapp/icecube/presentation/dataTable.xhtml):
<ice:form> <ice:panelGrid> <B><ice:dataTable id="table" var="tableRows"</B> value="#{dataTable.rowsList}" rows="3" resizable="true"> <ice:column> <f:facet name="header"> <ice:outputText value="#{icecube[ 'application.menu.presentation. dataTable.attribute.firstname']}"/> </f:facet> <ice:outputText value="#{tableRows.firstname}"/> </ice:column> </ice:dataTable> <B><ice:dataPaginator for="table"></B> <f:facet name="first"> <ice:graphicImage style="border:none;" url="#{iceFusionConsts.skinBase}/ ... / arrow-first.gif"></ice:graphicImage> </f:facet> <f:facet name="last"> <ice:graphicImage style=”border:none;” url=”#{iceFusionConsts.skinBase}/ ... / arrow-last.gif»></ice:graphicImage> </f:facet> </ice:dataPaginator> </ice:panelGrid> </ice:form>
The dataPaginator allows to define navigation controls. In our example, we reference icons that are part of the ICEfaces 1.8 standard skin Rime. The ICEfusion skins are based on Rime and with it, also the ICEcube skins. The dataTable tag defines an id attribute so that the dataPaginator can reference to it via its for attribute. The dataPaginator becomes active when the rows
attribute of the dataTable defines a number of lines that is smaller than the size of the list of objects defined via the value attribute.
If you define a dataPaginator tag, it is always rendered even if it doesn’t need to be. So, it is a good idea to check if the rows attribute of dataTable is really smaller than the size of the list of objects. You can use the result in the rendered attribute of the dataPaginator.
Dynamic data table
Static tables are easy to manage. You edit the tag definition and get a new column, or change the sequence of columns through cut and paste. In more complex applications that try to reach a higher level of reuse in the presentation layer, this kind of management is too infl exible. If the column definition varies during runtime, you may have to define a table for each variation. This can be a maintenance hell in
the long run. Alternatively, you use a component that can be configured for how the presentation will look. ICEfusion delivers a table tag that can work like this. It integrates the features from the static table above, but decides during runtime how columns are rendered.
The ICEfusion dynamic data table allows defining:
- The columns that are presented. So, a dedicated selection of object attributes can be done.
- The sequence of columns. So, the presentation order of object attributes can be freely defined.
In comparison to the implementation we used for the static data table, the dynamic data table definition is minimalistic. Here is an example from the ICEcube implementation (/src/main/webapp/icecube/presentation/dataTableDynamic.xhtml):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:ice="http://www.icesoft.com/icefaces/component" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jstl/core" xmlns:t="http://myfaces.apache.org/tomahawk" xmlns:icefusion= "http://icefusion.googlecode.com/icefusion"> <body> <ui:composition template="#{iceFusionConsts.templatePage}"> <ui:define name="title"> #{icecube['application.menu.presentation.dataTable .dynamic']} </ui:define> <ui:define name="content"> #{icecube['application.menu.presentation.dataTable .dynamic.text']} <ice:form> <icefusion:table valueBean="#{dataTable}" resizable="true"/> </ice:form> </ui:define> </ui:composition> </body> </html>
The ICEcube backing bean of the page and the backing bean of the table tag have to supply the missing functionality instead. The syntax for the table tag looks like this:
<icefusion:table valueBean="#{bean_that_implements_ITable}" resizable="true|false" rows="number_of_rows_to_show"/>
The resizable attribute and the rows attribute follow the description for the static data table. The valueBean attribute is the central part of this definition. It defines a bean that implements methods that deliver:
- The list of rows to show: The list has objects that implement the ITableRowSortable interface so that a column sorting is possible.
- The list of columns that have to be shown in the table: We use a LinkedHashMap here, which defines the attribute names and the resource
bundle IDs to use for multilingual presentation of the column headers. This kind of a Map allows you to keep the sequence of creation.
The backing bean of the page has to implement the ITable interface if it manages what the table tag has to show. Here is the definition for ITable (/src/main/java/com/googlecode/icefusion/ui/commons/form/ITable.java):
package com.googlecode.icefusion.ui.commons.form; import java.io.Serializable; public interface ITable extends Serializable { public List<ITableRowSortable> getRowsList(); public LinkedHashMap<String, String> getColumnsMap(); }
The backing bean of the ICEcube page example looks like this (/src/main/java/com/googlecode/icecube/presentation/DataTable.java):
package com.googlecode.icecube.presentation; import com.googlecode.icefusion.ui.commons.BackingBeanForm; import com.googlecode.icefusion.ui.commons.form.ITable; import com.googlecode.icefusion.ui.commons.form.ITableRowSortable; public class DataTable extends BackingBeanForm implements ITable { private ArrayList<DataTableRow4JavaAuthors> authors = new ArrayList<DataTableRow4JavaAuthors>(); private LinkedHashMap<String,String> attributes = new LinkedHashMap<String,String>(); protected void init() { authors.clear(); authors.add(new DataTableRow4JavaAuthors( "Rod","Johnson", "http://blog.springsource.com/author/rodj/",false)); authors.add(new DataTableRow4JavaAuthors( "Matt","Raible", "http://raibledesigns.com/",false)); // We define the order of attribute-to-column attributes.clear(); attributes.put("lastname","application.menu .presentation.dataTable.dynamic.attribute.lastname"); attributes.put("firstname","application.menu .presentation.dataTable.dynamic.attribute .firstname"); this.initialized = true; } public LinkedHashMap<String, String> getColumnsMap() { if (!this.initialized) { init(); } return this.getAttributes(); } public List<ITableRowSortable> getRowsList() { if (!this.initialized) { init(); } return this.getAuthors(); } }
The code shows the ITable methods—getColumnsMap() and getRowsList(). These deliver backing bean local definitions of a Map and a List, both of which are initialized in the init() method.