corner imagecorner image
FeaturesPluginsDocs & SupportCommunityPartners

Woodstock to ICEfaces Porting Guide - Part 1

This document guides you through the process of porting Woodstock applications to ICEfaces. The porting process is devised to be evolutionary in nature, allowing you to maintain a functional Woodstock application, while incrementally porting Woodstock pages to ICEfaces. The ultimate goal of the porting process is to entirely eliminate Woodstock from the application, leaving you with a pure ICEfaces application where you can take full advantage of all the rich features provided in the ICEfaces framework.

The migration support in ICEfaces is based on project-level coexistence with Woodstock, which means ICEfaces and Woodstock pages can coexist in the same web application. The approach is not intended to support page-level coexistence of ICEfaces and Woodstock, where components from both frameworks are included in the same page. That being said, subsequent releases of ICEfaces will include selectively ported Woodstock components that will exist as first-class citizens of the ICEfaces framework. The availability of these components will ease the page-level porting effort, but not eliminate it.

The majority of Woodstock applications are based on the Visual JSF project type in NetBeans, so this guide focuses on this particular migration path. If your application leverages Woodstock in some other programming model like Facelets, most of the concepts presented here still apply. The guide is presented in three parts.

Contents

Content on this page applies to NetBeans IDE 6.5  

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.

Adding the ICEfaces Plugins to 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 as follows.

  1. In the Main Toolbar, choose Tools > Plugins.

    The Plugin Manager opens.

  2. In the Availables tab of the Plugin Manager, type the first few letters of the ICEfaces plugins to display the plugins in the Plugin Manager.

    Confirm Import Settings Dialog
  3. Select the checkbox next to each plugin and click Install.
  4. In the NetBeans IDE Installer click Next. Accept the terms in all of the license agreements and click Install.

    Note: A dialog box may appear displaying a warning about third-party plugins.

  5. Restart the IDE.

Establishing a 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 shown in the following image.

New working example

Adding ICEfaces to an Existing Woodstock Application

The first step in the porting process is to add the ICEfaces framework to the project using the following steps.

  1. Access the Project Properties dialog by right-clicking the TwoPageCrudTable project and selecting Properties.
  2. In the Project Properties dialog box, select Frameworks and click Add. In the Add a Framework dialog box, select the Visual Web ICEfaces frameworks as shown in the following image.

    Adding the ICEfaces framework
  3. Complete the dialog by selecting Synchronous Update in ICEfaces Settings and clicking OK, as shown in the following image. 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.

    Project properties

Adding the ICEfaces framework to the project results in a number of changes, including:

  1. Configuration in web.xml is modified to include:
    • ICEfaces-specific context parameters
    • ICEfaces Servlets
    • ICEfaces Servlet mappings
  2. ICEfaces design and run time libraries are added.
  3. A template ICEfaces page called IcePage1.jsp is created.
  4. A template index.html page is created.

The project should be runnable as is, but with the introduction of index.html, you need to do one of the following:

  • Adjust the Run properties in Project Properties to specify a relative URL of /faces/Page1.jsp
  • Modify index.html to redirect to the appropriate page, something resembling the following code sample.
     <meta http-equiv="refresh" content="0;url=faces/Page1.jsp">     

Understanding 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 shown in the following image in a diff of these two pages. If you only use navigation.xml for navigation rules in imported projects, you should not have any problems. The following rules should help you resolve such conflicts.

Page template diff

As of NetBeans 6.5, the standard HTML tags <html>, <head>, and <body> are supported in the 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 Visual Web JSF 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 shown in the following code sample.

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 shown in the following code sample.

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 shows that it contains a calendar input, a couple input texts, and a drop down menu as the input controls requiring a backing model.

Creating a Page

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

Component Bindings

We start with the calendar, and eliminate the component bindings from CreatePage.java as follows.

  1. Replace the Calendar component import statement
    import com.sun.webui.jsf.component.Calendar;
    with a standard Java Date import statement.
    import java.util.Date;
  2. 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;
    }
  3. In the addButton_action() listener, remove the following 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 the following code.
<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 Text Field components with a similar set of modifications.

  1. Remove the Text Field component import statement.
    import com.sun.webui.jsf.component.TextField; 
  2. 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;
           }
  3. 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 the following code.
<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 Drop Down List component in a similar fashion.

  1. Remove the DropDown component import statement
    import com.sun.webui.jsf.component.DropDown; 
  2. 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;
    }
  3. 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 the following code.
<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 does not render the drop down list because the id tripType matched the selected value tripType. This can be 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 shown in the following image. For our working example, the page is called IceCreatePage.jsp.

Creating an ICEfaces page

Page Porting Basics

There are two likely scenarios that are encountered when embarking on a page porting exercise.

  1. 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.
  2. If the new ICEfaces page is to initially remain the same, with the intent of adding additional features only after the existing functionality has been reproduced, you should 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 them into 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 shown in the following image.
Copying and pasting code

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.

  1. 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 is 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.
  2. 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 identifies these components and provides 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 can copy the entire page and its backing beans to a new page and do your porting there, or you can build a new JSP page, and reuse the existing backing bean as is. For the working example we take the later approach and reuse the exising Page1.java backing bean. To complete the page port we need to do the following.

  1. Port Masthead.jspf
  2. 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 port it to ICEfaces by simply replacing the webuijsf: components with corresponding ice: components, as shown in the following image.

Masthead diff

The specific changes in the port include:

  1. 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 the following.
    <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">
  2. Changing <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"/>
  3. Changing <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 the following.
    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 components to replace a single Woodstock component.

Porting the page body

The following diff shows the changes required to port the content in the main panel grid.

Main panel diff

The resulting JSP code resembles the following code.

<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 following:

  1. The jsp include directive now specifies iceMasthead.jspf.
  2. <webuijsf:label/> is replaced with <ice:outputLabel/>, and value binding attribute name is changed from text to value.
  3. <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.
  4. <webuijdf:textField/> is replaced with <ice:inputText/>, and value binding attribute name is changed from text to value.
  5. <webuijsf:dropDown/> is replaces with <ice:selectOneMenu/> containing a child <f:selectItems/> for the list value binding.
  6. <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.
  7. <webuijsf:messageGroup/> is replaced with <ice:messages/>. Layout and style attributes have been added to <ice:messages/> to closely mimic <webuijsf:messageGroup/>.
  8. 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 functional 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 shown in the following image.

Navigation rules diff

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 Editor 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 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 shown in the following image.

Date validation

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 shown in the followin image.

<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 shown in the following image. City validation

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.

Summary

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.

See Also


This page was last modified: December 16, 2008