Jaimon's Blog

Migrating 10g JSF Web project with ADF Faces components in jspx pages to 11g Facelets pages using Rich components

Introduction

As of this writing (Feb 2010), there are no tools available to convert your 10g project into an 11g project using Rich components, let alone something that can convert my jspx pages into Facelets. JDeveloper 11g FAQ confirms that, you need to do manual migration if you want to use Rich components. As Oracle points out, you’ll need to do some code refactoring to make use of new functionalities available with JSF 1.2 and Rich components (and Facelets).

This post discusses a few points encountered during my by hand migration process I’ve done with a couple of 10g projects. If you are migrating to use Trinidad components instead of Rich components, then this paper would be more useful than my post.

At the end of this post, you can download a sample 11g Rich Component project with Facelets pages to get you going.

Why Facelets?

There are a number of good articles on this subject, so there is no point repeating any of that here. (See reference section for some useful links). For me, the main reasons for the conversion was the fact that JSP is deprecated from JSF 2.0, and Facelets is the new standard view technology, so at some stage, you’ll need to convert to Facelets. And also the Facelets pages render a bit faster.

Some other benefits like templating may not sound great to an ADF user as Oracle already had templating support from JDeveloper 10g.

Facelets support in JDeveloper

Although the usage of Facelets was possible with 10g as discussed here, there was little IDE support like code completion available to you. Although the support improved in 11g, it wasn’t perfect as John Stegeman explains here. But it is a lot better now with Patch 1 release on November 2009 (Version 11.1.1.2.0 onwards). So please update your JDeveloper 11g if you plan to use Facelets at all.

Skinning

In 11g, you can extend an existing skin rather than creating everything from scratch. The fusion desktop skin that comes with Patch 1 release looked great to us, and decided to use it instead of custom skinning. We changed a few styling details by adding some CSS styles and by overriding existing styles. You may find these posts on skinning useful

If you want to change your skin at run time, please see this forum post.

Cleaning up

It is always a good practice to clean up your project before doing the migration. One of the biggest clean up I did was to remove a lot of unnecessary bindings. Anyone remember this screen?
JDeveloper’s auto binding feature may be suitable for certain applications, but for many projects it only resulted in a binding hell. In 11g, this feature is not selected by default. It was surprising to see we only required a couple of bindings with next to nothing Java code changes (other than removing binding references) compared to hundreds of bindings we had. We could have removed our last few bindings with some source code changes, although we decided to keep the changes to a minimum. I prefer my Java code to be decoupled with JSF library as much as possible. It will make life easier with unit tests as well. And I certainly won’t be the only one to say decoupling is a good idea. Please see Cay Horstmann discusses about decoupling with JSF API here.  (Although he talks in a JSF 2 context, the principles are the same regardless of any version number)
Code re-factoring on view pages – Converting Jspx to Facelets

Changing a jspx page to a Facelets page is very straight forward as this Myfaces wiki explains. But as you might want to use Facelets functionalities like templating, custom tag libraries etc, this would be a perfect time to think and document your overall site design. You can also take out all those nasty f:verbatim tags and include HTML tags directly on your page. So if you ever used some thing like this in your old page,

 

<f:verbatim><hr/></f:verbatim>
outputText value=”#{backing_bean.msg}” />

 

This can now be changed to

 

<hr/>
#{backing_bean.msg}

 

 
Templating

Easy templating is one of the selling points of Facelets. There are good tutorials available on the net on this topic including this one from Jacob Hookom, the creator of Facelets. In our sample project, I’ve included a template file (template.xhtml) with a page header, content area and page footer. You can include any common functionality in your template file. If one or two pages in your application require things differently, you have the option to override them in those specific pages only.

Once the template is created you could start converting each jspx pages. Use the new gallery and select Facelets page (Please make sure “All Technologies” tab is selected)

Then you may start with this code and copy/paste the main content from jspx page, excluding anything that is already in template file.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
template="template.xhtml">
<ui:define name="pageTitle">Facelets Test Page</ui:define>
<ui:define name="content">
<!--
Copy/Paste main content from your jspx page here
-->
</ui:define>
</ui:composition>

You can override any named UI component you’ve defined on your template file.

While a lot of simple rich tags like outputText, forEach, panelBox etc. won’t need any modifications at all, tags like table or treeTable will require some attention. (Please see af:table issues section as well). It will be worthwhile to have a look at the online rich client demo at http://jdevadf.oracle.com/adf-richclient-demo/faces/components/index.jspx. Please see this link if you want to deploy the online demo on your own server. With the introduction of new components like Calendar, Carousel etc. it is very tempting to do a page redesign. Another enhancement we liked was the inline dialog boxes and pop-up windows. (You can see it in action on the sample project)

You can find the list of new features in 11g at http://www.oracle.com/technology/products/jdev/collateral/papers/11/newfeatures/index.html

If you have used JavaScript in your pages, you’ll find this post by Frank Nimphius very useful. One thing you’ll notice straight away is, there are no on event attributes (e.g. onclick) available in tags like af:commandButton. You’ll be required to use af:clientListener tag instead. Please see Frank’s blog for examples.

af:table issues

Oracle has done quite of lot of work with af:table component. It is more intelligent now, so it will only fetch the data as you scroll along, if you wish so, something similar to Yahoo Mail’s inbox. It is quite a useful feature if you have a big table, but at least in our case, the user experience wasn’t that great, especially when you scroll with your mouse scroll wheel. You’ll see quite a lot of “Fetching Data” messages. Again a change you’ll notice here is the lack of separate pagination controls. So even if you set rows=”15” on af:table, it is not going to put pagination controls when you have a table with more than 15 items. It isn’t entirely bug free too, as discussed here. I’ve provided a dirty fix on the forum, but as I mentioned there, it is something Oracle needs fixing.

Code reuse and Facelets custom tag libraries (Please see reference section for online material on this subject)

If you are displaying similar data in more than one page, you could make use of Facelets custom tag libraries to create a common component and reuse everywhere else. When working with ADF Faces, there are a few catches though. One of them is the usage of partialTriggers in tag libraries. See this example here,

On test.xhtml, we are including the custom tag library with this line

 

<j:sdetails value=”#{test.msg}” partialTriggers=”cmdButtonId” />

 

On the tag library file sdetails.xhtml, if we include the partialTriggers directly as shown below, it will result in a run time java.lang.IllegalArgumentException: Cannot convert x of type class java.lang.String to class [Ljava.lang.String; as ADF Faces expect the attribute value of partialTriggers as a String array.

 

<af:outputText value=”#{value}” partialTriggers=”#{partialTriggers}” />

 

To pass in an array, we could define a function in our test.tablig.xml file as,

<function>
<function-name>getStringArray</function-name>
<function-class>uk.co.jaimon.ft.Test</function-class>
java.lang.String[] getStringArray(java.lang.String)
</function>


And declare this static method in Test.java file as,

public static String[] getStringArray(String string) {
if(string == null || "".equals(string)) {
return new String[0];
}else {
return string.split(" ");
}
}

Now on the taglib file, we can use the following line to make it work,

<af:outputText value="#{value}" partialTriggers="#{j:getStringArray(partialTriggers)}" />

You can see the full implementation on the sample project.

Navigation specified in faces-config.xml doesn’t work for pop-ups when used with Rich Components!

That was a surprise, and took a while to figure out Oracle has moved all their extension work on navigation to task flow files.

Let’s say you had a navigation defined in faces-config.xml as,

<navigation-rule>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>dialog:nameSearch</from-outcome>
<to-view-id>/nameSearch.jspx</to-view-id>
</navigation-case>
</navigation-rule>

To make this work under 11g, first you need to add an ADF task flow page. From new gallery, select ADF Task Flow off Web Tier/JSF category and click OK.

On the following page, uncheck the box “Create as Bounded Task Flow” as shown here,

And modify the content with the following lines,

<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
<view id="nameSearch">
<page>/nameSearch.xhtml</page>
</view>
<control-flow-rule>
<from-activity-id>*</from-activity-id>
<control-flow-case>
<from-outcome>dialog:nameSearch</from-outcome>
<to-activity-id>nameSearch</to-activity-id>
</control-flow-case>
</control-flow-rule>
</adfc-config>

Again, the sample project includes a working implementation.

Code re-factoring on Java code

This could be a simple task or a bigger one depending on how many bindings you’ve used in your project, and how much re-factoring you want to do. What I did was to replace the word Core with Rich using Search/Replace in Files option. So basically, your CoreTable becomes RichTable, CoreInputText becomes RichInputText etc. And in imports, replace all oracle.adf.view.faces.component.core. with oracle.adf.view.rich.component.rich.

JDeveloper 11g/WebLogic is only certified to work with JDK 1.6. Make use of the new functionalities available with JDK 1.5 and 1.6 like Generics, new for loops, auto boxing etc, if you aren’t already using JDK5 features in your 10g projects. Please see the release notes for JDK 1.5 and JDK 1.6 for more details.

Although OC4J R3 (10.1.3) was a J2EE 1.4 Server, it also supported EJB 3.0 and JPA, which were part of JEE5. If you are using EJB beans, then you might be better off using the migration wizard in JDeveloper 11g. Once migrated, you can convert your jspx to Facelets pages and change backing beans accordingly. You’ll be required to modify web.xml for Facelets support and take out the JSP library as well.  Some of these post might be useful in EJB migration

Migrating data sources

This Oracle document explains about various data sources migration options. What I did was to create IDE connections and then just drag the connection to different applications via Database Navigator. This will result in creation of connections.xml in .adf/META-INF folder on your application folder. Once you add the connection, JDeveloper will create necessary JDBC module when you run or debug your application with the integrated WebLogic server.

Obtaining data sources from your Java code.

JNDI lookup code also needs some modification if you’ve used code similar to,

DataSource ds = (DataSource) ic.lookup("jdbc/preProdDS");

You’ll need to change it to the following line to make it work with WebLogic server,

DataSource ds = (DataSource) ic.lookup("java:comp/env/jdbc/preProdDS");

Just a side note, here the connection name you set up in JDeveloper will be just “preProd” and not “preProdDS”.

IE6 support

Well, the simple answer is, there is none. If you open your application on IE6, a JavaScript alert will pop-up displaying the list of browsers Oracle support.

In a way, it is a good thing, so we can finally get those IE6 users to upgrade. But that can also be the problem, getting them to upgrade before they can use your 11g application. If you desperately needs IE6 support, then you should stick with Trinidad components with 11g and not Rich components.

Rendering issues on IE8

Although IE8 is officially supported with the patch 1 release as mentioned here, there are still some rendering issues with certain components (as of February 2010). One of them is the treeTable component. If you’re on IE8, open test.jspx from my sample application and click on Tree Table Issue button.

As you can see, when you scroll, some texts are getting displayed outside the scrolling area. This doesn’t happen in any other browsers I’ve tested. Hopefully Oracle will fix it in their next release.

Sample Application

 You can download an 11g sample application from here. Run index.jsp or test.xhtml to start the application. It show cases some of the functionalities we’ve discussed on this post, including usage of Facelets templates, tag library, inline pop-ups, ADF-C page flow etc.

Have a happy migration!

Jaimon Mathew

References:

February 6, 2010 Posted by | Uncategorized | , , , , , , , , | Leave a comment