Wednesday, July 25, 2007

Basic UI Design With JavaServer Faces (Pt. I)

In May, I wrote a post about getting JSP-based webapps to use JSF. Based on that post, we will convert our existing timecard utility to a JSF-based web application. The steps in the JSF post are largely good enough, with exceptions that I mention in here.

Be prepared to write a whole lot more code. The coding isn't hard - it's the repetitiveness and time you spend doing it that takes the steam out of it.
Beyond changes required by JSF (config files), we only change the JSP (add JSF markup) and bean (make it managed). In the end, we still get the same look and the application accomplishes the same things as before.
This implementation has 60+ components (areas, fields) on the page that need to be updated dynamically. The bulk of them are in the display table itself, and the rest are the various total and summary fields. We keep it simple in this example and use only <h:view>, <h:form>, <h:inputText>, <h:outputText>, and <h:commandButton> for JSF markup, although we could have just as easily implemented a <h:panelGrid> for the table.
You have to start worrying about session management. Case in point, if the view expires (either because the application was restarted or the session expired), you start getting exceptions like "javax.servlet.ServletException: viewId:/index.faces - View /index.faces could not be restored" caused by javax.faces.application.ViewExpiredException. That means you have to start over, as JSF emphasizes navigation/page flow (you need to start at the beginning).
JSF does not cure issues you already had in the JSP solution - all the bottlenecks and inefficiencies in algorithms will still be there. In fact, you might end up tossing lots of code, such as those that depend on parameters and field names passed from the client. It's true that pure HTML is generated by the JSF framework, but fields never have consistent names, especially when the view is regenerated.
I might add that JSF introduces its own issues - hints that designing a JSP app can be quite different from JSF - the need to plan everything and stick to the plan. They just behave differently.

Source code:
# The JSF-aware JSP file (index.jsp).
# The overhauled bean to support JSF (TimecardBean2.java).
# The other classes and pages remain the same.

After deploying the webapp, it's now available at <domain>:<port>/<webapp>/index.faces (as opposed to the usual <domain>:<port>/<webapp>/, which would have called index.jsp). Even with the <welcome-file> element set in the deployment descriptor to open the *.faces page, SJSAS web server does not get it right. Though, you can set NetBeans to open the page specifically (debug/run).

Some NetBeans 6.0 (M9) quirks:
(1) You don't get the option to reset encapsulated attributes' access levels when generating setters/getters, so remember to precede them with 'private' during declaration.
(2) The IDE no longer has a means to select all variables [Select All button] for which you are generating setters/getters. In fact, it also no longer allows you to select which getters or setters you want on one screen - how it was done in version 5.5].
(3) Whenever you add breakpoints in debug mode, you have to "debug project" again = compiling and deploying to a debug-mode server. Quite inconvenient, as some may wonder why breakpoints are not working.
(4) Code completion is case sensitive. The whole idea of this feature should be to reduce having to remember variables in your classes/pages. Now I have to remember whether I capitalized something or not?