Woodstock to ICEfaces Porting Guide - Part 1
Part 1 of this guide examines
the steps required to port a single page in an existing Woodstock
application to an ICEfaces page. The following topics are
discussed:
At the completion of this guide you will be well-positioned to begin
porting your Woodstock application to ICEfaces. Beyond this
guide, you can examine issues related to porting data tables in Woodstock to ICEfaces Porting Guide -
Part 2. The completed project for this step of the guide is
available here.
Installing the
ICEfaces Plugins in NetBeans
Woodstock migration support is available for the first time in the
ICEfaces 1.7.2SP1 release, which is aligned with the NetBeans 6.5
release. Prior to embarking on a porting exercise you will need
to upgrade to NetBeans 6.5, import your Woodstock Visual JSF project,
and install the ICEfaces plugins for NetBeans. The steps required to
install the ICEfaces plugins are:
- Registered ICEfaces community members can download the
ICEfaces/NetBeans integration bundle here.
The bundle is located under IDE Tool
Integrations > NetBeans, and is called ICEfaces-1.7.2-SP1-NetBeans-6.5-modules.zip.
Unpack the bundle somewhere that you can access it from
NetBeans.
- Install the ICEfaces plugins into NetBeans from the Tools > Plugins dialog, using
the Downloaded tab. The
Add Plugins button is used
to select the ICEfaces plugins which are called com-icesoft-faces-vwp-ide.nbm and com-icesoft-ide-netbeans-libs-module.nbm.
Once you have selected the plugins, you should see something like this,
and just need to hit the Install
button.

Working Example
The working example for this guide is based on a readily available
NetBeans sample project call Two
Page CRUD With Table. It is chosen for it's relative
simplicity, and because it is a multi-page application with
navigation. Over the course of the migration we will add the
ICEfaces framework, add ICEfaces pages, and port existing Woodstock
pages to ICEfaces. We will also establish navigation between ICEfaces
and Woodstock pages. You can get your own working copy of the
example using the File > New
Project dialog and choosing from Samples > Java Web (Visual JSF) >
Two Page CRUD With Table, as illustrated below.

Adding The ICEfaces
Framework
The first step in the porting process is to add the ICEfaces framework
to the project using the following steps.
- Access the Project Properties
Dialog by right clicking the TwoPageCrudTable
project and selecting Properties
from the context menu.
- From the Project Properties
Dialog select Frameworks
and click the Add
button. From the Add a
Framework Dialog select the Visual
Web
ICEfaces frameworks as illustrated below.

- Complete the dialog by selecting Synchronous Update in the ICEfaces
Settings and hitting the OK
button, as illustrated below. Synchronous updates simplify
the client/server communications in applications where ICEfaces Ajax Push
capabilities are not being leveraged. Synchronous updates most
closely match the existing behavior of the application. The
other setting, Concurrent DOM View,
is discussed in Part 3 of this
guide. For now, it should be left unchecked
.
Adding the ICEfaces framework to the project results in a number of
changes, including:
- Configuration in web.xml is modified to include:
- ICEfaces-specific context parameters
- ICEfaces Servlets
- ICEfaces Servlet mappings
- ICEfaces design and run time libraries are added.
- A template ICEfaces page called IcePage1.jsp
is created.
- A template index.html
page is created.
The project should be runnable as is, but with the introduction of the index.html, you need to either:
- Adjust the Run
properties in the Project Properties to specify a relative URL of /faces/Page1.jsp, or
- Modify the index.html
to redirect to the appropriate page, something like...
<meta
http-equiv="refresh" content="0;url=faces/Page1.jsp">
The ICEfaces Page Template
The ICEfaces NetBeans plugin provides JSF Visual Design capabilities
similar to the Woodstock-based JSF Visual Design capabilities that your
existing project is based on. The ICEfaces page template strongly
resembles the Woodstock template as illustrated below in a diff of
these two pages.

As of NetBeans 6.5 the standard HTML tags <html>, <head>, and <body> are supported in design view so
ICEfaces replacements are not required for <webuijsf:html>, <webuijsf:head>, and <webuijsf:body> and the
standard HTML tags are used in the ICEfaces page template. Any
page porting
exercise will involve migrating the page content in the <webuijsf:form> of the
Woodstock page to the <ice:form>
in the replacement ICEfaces page.
Woodstock Component
Bindings
Before you start porting Woodstock pages to ICEfaces pages, there is a
potential problem with the application data model that you might need
to address. If your JSF Visual Project was created prior to the
NetBeans 6.1 release, and you have not already refactored to eliminate
the component bindings, it will be necessary to do so. In the
case of our working example, that refactoring has not occurred, so we
will use it to describe the process of achieving this refactoring.
A quick review of JSF component bindings vs. value bindings is in order
before proceeding. A component binding binds the view component
to a component instance in the backing bean as illustrated below:
The view component definition,
<h:outputText
binding="#{myBean.someOutputText}" />
is bound to an instance of HtmlOutputText
in the backing bean.
public
class MyBean {
HtmlOutputText
someOutputText;
public
HtmlOutputText getSomeOutputText() {
return someOutputText;
}
public
void setSomeOutputText(HtmlOutputText outputText) {
someOutputText = outputText;
}
}
While component binds facilitate manipulation of the component directly
from Java code, the view and the model become tightly coupled through
the component class itself. When you consider porting away from a
particular component you are forced to port the model as well, because
the component instance will no longer be present. In contrast,
value
bindings bind the view component to a property in the backing bean as
illustrated below:
The view component definition,
<h:outputText
value="#{myBean.someText}" />
is value bound to an instance of String in the backing bean.
public
class MyBean {
String someText;
public String
getSomeText() {
return someText;
}
public
void setSomeText(String text) {
someText = text;
}
}
This completely separates the view from the model, and ensures that the
backing bean can be represented as a portable POJO. This is the
essence of the refactoring that must occur prior to porting the page to
ICEfaces.
Eliminating Component Bindings in the Working Example
We will work with the simplest page, CreatePage.jsp,
in the working example to fully illustrate the process of factoring out
the component bindings. A quick look at the page illustrates that
it contains a calendar input, a couple input texts, and a drop down
menu as the input controls requiring a backing model.

And you can see in CreatePage.jsp,
these input components currently have component bindings.

We will start with the calendar, and eliminate the component bindings
from CreatePage.java as
follows:
- Replace the Calendar
component import statement
import com.sun.webui.jsf.component.Calendar;
with a standard Java Date
import statement
import java.util.Date;
- Replace dateCalendar bean property code
private Calendar dateCalendar = new Calendar();
public Calendar getDateCalendar() {
return dateCalendar;
}
public void setDateCalendar(Calendar c) {
this.dateCalendar = c;
}
with date bean property code
private Date depDate = new Date();
public Date getDate() {
return depDate;
}
public void setDate(Date d) {
this.depDate = d;
}
- In the addButton_action()
listener remove the line
java.util.Date depDate = (java.util.Date)
dateCalendar.getValue();
Now we can return to the JSP
code and modify the calendar component declaration
<webuijsf:calendar binding="#{CreatePage.dateCalendar}"
id="dateCalendar" ... />
with
<webuijsf:calendar selectedDate="#{CreatePage.date}"
id="dateCalendar" ... />
At this point we have a functional CreatePage.jsp
where the calendar
binding has been converted from a component to a value binding.
From here we move on to the textField
components with a similar set of modifications.
- Remove the TextField
component import statement
import
com.sun.webui.jsf.component.TextField;
- Replace TextField bean property code
private TextField fromCity = new TextField();
public TextField
getFromCity() {
return fromCity;
}
public void
setFromCity(TextField tf) {
this.fromCity = tf;
}
private TextField toCity =
new TextField();
public TextField getToCity()
{
return toCity;
}
public void setToCity(TextField tf) {
this.toCity = tf;
}
with String bean
property code
private String fromCity = "";
public String getFromCity() {
return fromCity;
}
public void
setFromCity(String s) {
this.fromCity = s;
}
private String toCity = "";
public String getToCity() {
return toCity;
}
public void setToCity(String s) {
this.fromCity
= s;
}
- In the addButton_action()
listener modify the lines
tripDataProvider.setValue("TRIP.DEPCITY", rowKey, fromCity.getValue());
tripDataProvider.setValue("TRIP.DESTCITY", rowKey, toCity.getValue());
to use the String bean properties directly
tripDataProvider.setValue("TRIP.DEPCITY", rowKey, fromCity);
tripDataProvider.setValue("TRIP.DESTCITY", rowKey, toCity);
And back in the JSP
code we modify the textField
declarations
<webuijsf:textField binding="#{CreatePage.fromCity}"
id="fromCity"/>
<webuijsf:textField binding="#{CreatePage.toCity}"
id="toCity"/>
with
<webuijsf:textField text="#{CreatePage.fromCity}"
id="fromCity"/>
<webuijsf:textField text="#{CreatePage.toCity}"
id="toCity"/>
At this point we again have a functional CreatePage.jsp where four of the
five component bindings have been converted to value bindings.
The last step is to modify the dropDown
in a similar fashion.
- Remove the DropDown
component import statement
import
com.sun.webui.jsf.component.DropDown;
- Replace DropDown bean property code
private DropDown tripType = new DropDown();
public DropDown
getTripType() {
return tripType;
}
public void setTripType(DropDown dd) {
this.tripType
= dd;
}
with String bean
property code
private String tripType = "";
public String getTripType() {
return tripType;
}
public void setTripType(String s) {
this.tripType = s;
}
- In the addButton_action()
listener modify the line
tripDataProvider.setValue("TRIP.TRIPTYPEID", rowKey,
tripType.getSelected());
to use the tripType
bean properties directly
tripDataProvider.setValue("TRIP.TRIPTYPEID", rowKey, tripType);
And finally, back in the JSP
code we modify the dropDown
declarations
<webuijsf:dropDown binding="#{CreatePage.tripType}"
id="tripType" items=... />
with
<webuijsf:dropDown selected="#{CreatePage.tripType}"
id="tripType1" items=... />
Now we have a functionally equivalent CreatePage.java
backing bean that
has no Woodstock-specific component bindings and is portable enough to
proceed with the page conversion to ICEfaces.
Notes:
- For some reason the
NetBeans visual editor would not render the dropDown because the id tripType matched the selected value
tripType. This was
corrected by modifying the id to eliminate the match.
- The IntegerConverter is
no longer required on the page, but it is used in a binding from UpdatePage.jsp, so it is left in
the code.
Creating a New ICEfaces
Page
Before we begin the process of porting a Woodstock page to ICEfaces, we
need a template ICEfaces page to port into. The context menu Web Pages > New > ICEfaces Visual
Web JSF Page... will result in a new page dialog as illustrated
below. For our working example, the page is called IceCreatePage.jsp.

Page Porting Basics
There are two likely scenarios that will be encountered when embarking
on a page porting exercise.
- If the new page design is significantly different than the
existing page design and will take advantage of the extended features
and components available in ICEfaces, the recommenced approach is
to build an entirely new ICEfaces page using the visual editor and not
attempt to port the existing Woodstock page. It is likely that
the existing backing beans can be reused, but it may be necessary to
augment those beans to support the new page functionality.
- If the new ICEfaces page will initially remain the same, with the
intent of adding additional features only after the existing
functionality has been reproduced, you will want to preserve the
original page structure as much as possible, and reuse the existing
backing beans. The recommended approach is to use the JSP editor
to cut the page contents from the old page, and paste it in to the new
ICEfaces page. From there you can perform component-by-component
conversion using the JSP editor. Considering our working example
with CreatePage.jsp being
ported to IceCreatePage.jsp,
the resulting starting point for the page conversion is illustrated
below.

Component-by-component
Porting
Porting away from Woodstock components to ICEfaces components must be
addressed on a component by component basis. To assist in this process
a Component
Mapping Matrix is available that provides
component to component mappings, and attribute comparisons. We
now examine the variations on component porting that you will likely
encounter.
Standard JSF Component Porting
Components from the standard JSF namespaces xmlns:f="http://java.sun.com/jsf/core"
and xmlns:h="http://java.sun.com/jsf/html" do not require porting as
they can coexist with other ICEfaces components in the page. In
the case of the h: components,
ICEfaces also provides direct replacements from the ice: namespace, so you can simply
change the prefix on these components to get the extended ICEfaces
versions. The advantage to the ice:
versions is they support all the ICEfaces automatic Ajax features such
as partial submit. A general rule of thumb is, if the h: component has any dynamic
behavior associated with it, it is a candidate for conversion to an ice: component. If, on the
other hand, it is static element in the page, there is no real
advantage to converting it.
Woodstock Component Porting
With the ICEfaces 1.7.2SP1 release all components from the Woodstock
namespace xmlns:webuijsf="http://www.sun.com/webui/webuijsf"
must be ported to ICEfaces components. In subsequent ICEfaces
releases a certain subset of webuijsf:
components may be directly supported and will not require porting, but
until then you must consider porting all of them. During the
porting process you will encounter two likely scenarios.
- There is a direct replacement in the ICEfaces component suite
for the Woodstock component being replaced. A simple example is <ice:outputLabel/> replacing <webuijsf:label/>. In
this case, it will be necessary to adjust the attributes list to match
those available in the ICEfaces component. Although you are
dealing with a direct component replacement, it is important to
understand that the components may not have the exact same feature set
so adjustments may be necessary. The component porting matrix
identifies attribute similarities and differences, and provides general
guidance related to behavioral differences between the ICEfaces and
Woodstock counterpart.
- There is no direct replacement in the ICEfaces component suite
for the Woodstock component being replaced. An example of this is
<wiebuijsf:addRemove>
that includes two lists and a mechanism to move element back and forth
between the lists. In this case, a group of ICEfaces components
may have to be combined to achieve the functional equivalent.
Again, the component porting matrix will identify these components and
provide guidance on how to achieve a port to ICEfaces. As an
aside, some subset of this class of components will likely be
prioritized for inclusion as first-class components in subsequent
releases of ICEfaces.
Porting the Working
Example Page
Several different strategies can be taken when porting a page from
Woodstock to ICEfaces. You could copy the entire page and its
backing beans to a new page and do your porting there, or you could
build a new JSP page, and reuse the existing backing bean as is.
For the working example we will take the later approach and reuse the
exising Page1.java backing
bean. To complete the page port we need to:
- Port the masthead.jspf
- Port the main panelGrid in CreatePage.jsp
Porting the masthead
The first step in porting the page is to port the Masthead which is
included at the top of each page. To achieve this we need to copy
the existing Masthead.jspf to
iceMasthead.jspf and ported to
ICEfaces by simply replacing the webuijsf:
components with corresponding ice:
components, as illustrated in the diff below.

The specific changes in the port include:
- Modification of the namespace from
<div style="height: 155px; width: 760px; -rave-layout: grid"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html" xmlns:webuijsf="http://www.sun.com/webui/webuijsf">
to
<div style="height: 155px; width: 760px; -rave-layout: grid"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ice="http://www.icesoft.com/icefaces/component">
- Change <webuijdf:staticText/> declarations in the title panelGrid from
<webuijsf:staticText
id="appName" style="color: rgb(255, 255, 255); font-family:
Georgia,'Times New Roman',times,serif; font-size: 24px; font-weight:
bold" text="Two Page CRUD With Table"/>
<webuijsf:staticText
id="poweredBy" style="color: #ffffff; font-family: font-family:
Georgia,'Times New Roman',times,serif; font-size: 10px" text="Empowered by NetBeans 6"/>
to
<ice:outputText id="appName"
style="color: rgb(255, 255, 255); font-family: Georgia,'Times New
Roman',times,serif; font-size: 24px; font-weight: bold" value="Two Page CRUD With Table"/>
<ice:outputText
id="poweredBy" style="color: #ffffff; font-family: font-family:
Georgia,'Times New Roman',times,serif; font-size:
10px"
value="Empowered by NetBeans 6"/>
- Change <webuijsf:imageHyperlink/> declarations in the navPanel panelGrid from
<webuijsf:imageHyperlink
id="home" imageURL="/resources/home.gif" target="_blank" text="Home"
url="http://visualweb.netbeans.org/"/>
<webuijsf:imageHyperlink
id="help" imageURL="/resources/help.gif" target="_blank" text="Help"
url="readme.html"/>
to
<ice:outputLink id="home"
target="_blank" value="http://visualweb.netbeans.org/">
<ice:graphicImage id="graphic1" value="./resources/home.gif"/>
<ice:outputText id="out1" value="home"/>
</ice:outputLink>
<ice:outputLink id="help"
target="_blank" value="readme.html">
<ice:graphicImage id="graphic2" value="./resources/help.gif"/>
<ice:outputText id="out2" value="help"/>
</ice:outputLink>
In this case we use multiple ICEfaces component to replace a
single Woodstock component.
Porting the page body
The following diff illustrates the changes required
to port the content in the main panel grid.

The resulting JSP code looks like:
<ice:form id="form1">
<div style="position: absolute; left: 0px; top:
0px">
<jsp:directive.include
file="iceMasthead.jspf"/>
</div>
<h:panelGrid id="mainPanel" style="margin: 5px;
padding: 5px; left: 0px; top: 160px; position: absolute; width:
760px">
<h:panelGrid columns="2"
id="tripPanel" style="">
<ice:outputLabel id="label1" value="Date"/>
<ice:selectInputDate value="#{CreatePage.date}" id="dateCalendar"
renderAsPopup="true">
<f:convertDateTime timeZone="MST"/>
</ice:selectInputDate>
<ice:outputLabel id="label2" value="From"/>
<ice:inputText value="#{CreatePage.fromCity}" id="fromCity"
partialSubmit="true" required="true"/>
<ice:outputLabel id="label3" value="To"/>
<ice:inputText value="#{CreatePage.toCity}" id="toCity"
partialSubmit="true" required="true"/>
<ice:outputLabel id="label4" value="Trip Type"/>
<ice:selectOneMenu value="#{CreatePage.tripType}" id="tripType1">
<f:selectItems id="tripSelect"
value="#{CreatePage.triptypeDataProvider.options['TRIPTYPE.TRIPTYPEID,TRIPTYPE.NAME']}"/>
</ice:selectOneMenu>
</h:panelGrid>
<h:panelGrid columns="2"
id="buttonPanel" style="">
<ice:commandButton action="#{CreatePage.addButton_action}"
id="addButton" value="Add"/>
<ice:commandButton action="#{CreatePage.cancel_action}" id="cancel"
value="Cancel" immediate="true"/>
</h:panelGrid>
<ice:messages
id="messageGroup1" layout="table" style="color:red;"/>
</h:panelGrid>
</ice:form>
The specific changes in the port include:
- The jsp include directive now specifies iceMasthead.jspf
- <webuijsf:label/> is
replaced with <ice:outputLabel/>,
and value binding attribute name is changed from text to value.
- <webuijdf:calendar/> is replaced with <ice:selectInputDate/>.
In this case there is no direct replacement for the maximum and minimum
date values, so it would be necessary to add a validator to the
ICEfaces component to match the functionality in the Woodstock
component. This is an exercise left to the reader. One other
issue related to selectInputDate
is managing the timezone properly. A lengthy discussion is beyond
the scope of this guide, so for simplicity we use a standard
f:convertDataTime and specify a fixed timezone that match the timezone
the server is running in. For accurate results modify this to
your timezone.
- <webuijdf:textField/> is replaced with <ice:inputText/>,
and value binding attribute name is changed from text to value..
- <webuijsf:dropDown/> is replaces with <ice:selectOneMenu/> containing a child <f:selectItems/> for the list value binding.
- <webuijsf:button/> is
replaced with <ice:commandButon/>,
and value binding attribute name is changed from text to value. The actionExpression attribute is also
changed to an action.
- <webuijsf:messageGroup/> is
replaced with <ice:messages/>.
Layout and style attributes have been added to <ice:messages/> to closely
mimic <webuijsf:messageGroup/>.
- One minor change to the
style of the panelGrid
id="mainPanelGrid" is required. For the page to render
properly height:100% must be
removed from the style
attribute.
We now have a fully function ICEfaces replacement page for CreatePage.jsp. The next step
is to modify the navigation rules to go to and from IceCreatePage.jsp.
Page Navigation
With Woodstock the request path is defined by the Servlet mapping
/faces/* through the standard Faces Servlet. With ICEfaces
the request path is defined by the Servlet mapping*.iface through the ICEfaces Persistent Faces Servlet. Because different Servlets
are used for these request paths, it is necessary to use redirects when
navigating to and from ICEfaces pages. The changes required to
modify the navigation rules for the working example are illustrated
below.

The resulting navigation rules are:
<navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>createCase</from-outcome>
<to-view-id>/IceCreatePage.iface</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>updateCase</from-outcome>
<to-view-id>/UpdatePage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/IceCreatePage.jsp</from-view-id>
<navigation-case>
<from-outcome>created</from-outcome>
<to-view-id>/faces/Page1.jsp</to-view-id>
<redirect/>
</navigation-case>
<navigation-case>
<from-outcome>canceled</from-outcome>
<to-view-id>/faces/Page1.jsp</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
As you can see, Page1.jsp now
navigates to IceCreatePage.iface using a redirect as the outcome of the Create button, and IceCreatePage.jsp navigates back to Page1.jsp using a redirect as
the outcome of the Create and Cancel buttons.
Note: You cannot use the
visual page flow designer to make the necessary changes to incorporate
ICEfaces navigation rules.
Automatic Ajax
With the functional ICEfaces page now in place you can begin to explore
some of the Automatic Ajax features that the framework delivers -
without you altering a single line of code. Intelligent form
processing is one such feature, where the application can react to the
user on a field by field basis instead of processing the entire form
when it is submitted. As an example, simple type some gibberish
into the date field and then tab out of that field to the next.
You will see that validation on the date field runs immediately and
informs you that an invalid date has been entered, as illustrated below.

A capability called partial submit is responsible for this
behavior. Basically, a partial submit occurs as focus leaves the
date field, which causes the JSF lifecycle to run. The submit is
partial in that it will not validate the entire form, so you don't see
validation messages for fields that have not been visited yet.
Because the lifecycle runs it is possible to add business logic that
analyzes the users input and adjust the form accordingly. In our
case we have simply allowed the validation to run on the date
input.
We will now extend the intelligent form processing by requiring that
the From and To city fields are filled in prior
to submitting the form. This is achieved by turning on the partialSubmit and required attributes in the
inputText fields, as illustrated below.
<ice:inputText
value="#{CreatePage.fromCity}" id="fromCity" partialSubmit="true" required="true"/>
<ice:inputText
value="#{CreatePage.toCity}" id="toCity" partialSubmit="true" required="true"/>
If you rerun the application now, enter a valid date and then tab
through the From City inputText, you will see validation occurring immediately as illustrated below.

So you can see a more interactive form can be presented to the user
with very little effort using ICEfaces. Of course you could add
more sophisticated processing like checking the city against a database
of valid destinations, and disabling the Add button until a valid form has
been completed. Have a look at the ICEfaces Address Form Demo as another example of intelligent form processing.
Finished Part 1
You have now completed Part 1 of the Woodstock to ICEfaces Porting
Guide. The complete project up to this point can be downloaded
here.
At
this point you can go back to the table of contents, or
move on to Part 2 of the guide,
which focuses on porting a data table from Woodstock to ICEfaces.