Friday, May 29, 2009

Tip: Use Facelets 1.1.15 in JBoss 5.x

I've begun my research into RichFaces, and decided to actually read their developer guide instead of just winging it. Sometimes I do crazy things, I know. Anyway, one of their initial suggestions was to get a plain JSF application in place and working, and I thought this was a decent starting point - that way, any anomalies could be more easily traced as I added RichFaces stuff.

So I put a plain vanilla Facelets-JSF app together (i.e., one that doesn't use a third-party component set, like IceFaces or RichFaces) , and got it working just fine on JBoss 4.2.2 (here I'm using Facelets 1.1.14). However, with my migration to JBoss 5.1, this rather dumb prototype stopped working, with this exception on initial deployment of the webapp:

SEVERE [compiler] Missing Built-in Tag Libraries! Make sure they are included within the META-INF directory of Facelets' Jar
15:35:25,318 SEVERE [viewhandler] Error Rendering View[/index.xhtml]
java.lang.NullPointerException
at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49)
at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
at com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95)
at com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:524)
.............

On subsequent page loads, the "Missing Built-in Tag Libraries" message stopped appearing, but the NPE on NamespaceHandler continued to happen. Googling on the NPE was not entirely fruitful, but searching against the tag libraries problem led me to various known solutions; I addressed it by using the 1.1.15 version of Facelets.

For decent guidance on constructing a simple Facelets web app, here's a nice Facelets tutorial.

Thursday, May 28, 2009

Netbeans + JBoss 4.2/5.x + IceFaces + Facelets: Gotcha

On creating a new WebApp project in NetBeans 6.x, I noticed a number of frameworks offered that support various technologies. Since I was prototyping a JSF-Facelets app, I chose the Facelets framework; as a result, NetBeans added the jsf-facelets.jar to my project libraries (which means these jars would be deployed as part of the warfile). I'll now file that decision in the "seemed like a good idea at the time" category: NetBeans users, here's a heads-up; please read on.

My goal was to compare RichFaces and IceFaces component sets (about which I'll post my findings later). Starting with IceFaces 1.8, I added dependencies as their documentation guided me for the JBoss 5.x app server - including the icefaces-facelets.jar, which I assumed was their own icefaces-specific layer above the standard Facelets distro. As it turns out, not so much.

On putting together a simple JSF page with Facelets tags, the page load yielded this exception:

java.lang.NullPointerException
com.icesoft.faces.facelets.D2DFaceletViewHandler.renderResponse(D2DFaceletViewHandler.java:268)
com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:153)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110)

........

This seemed to point to a problem between IceFaces and Facelets, so my first instinct was to think that JBoss 5.x already had the Facelets classes loaded, and I was confusing things by adding my own version of these. As it turned out, I was on the right track...but more blind leads were to follow: in trying to reload the page, I got this exception:
java.lang.IllegalStateException: BaseClassLoader@144e022{vfsfile:}
classLoader is not connected to a domain (probably undeployed?) for class
javax.servlet.jsp.SkipPageException
This made me think that the removal of the Facelets jar was a mistake. Actually, no it was not; my mistake was trying to reload the page too quickly after redeploying. JBoss 5.0 takes a bit longer to complete a redeployment than I expected; had I simply waited another 5-10 seconds before reloading the page, I would have seen my original NPE problem solved instead of thinking I'd traded it for a different one.

What made this more confusing was that I tried the same webapp in JBoss 4.2, and had no problem at all. The IceFaces documentation around dependencies for JBoss 4.x vs 5.x is exactly the same; so it was mysterious why the webapp would work OK in 4.2 but not in 5.x.

After a bit more experimentation, I stumbled on the answers to all of the above:
  1. The standard Facelets jar should not be deployed when icefaces-facelets.jar is deployed; the latter appears to be an IceFaces-specific adaptation of the standard. This means NetBeans users should not choose the Facelets framework for a new WebApp project if they are going to be using Facelets with IceFaces.
  2. JBoss 4.2 classloading masks this issue by (apparently) loading the IceFaces version of these classes instead of the standard version, so things worked out just fine with 4.2.
  3. JBoss 5.0 loads the standard version of Facelets classes first (apparently), hence the problem.
  4. JBoss 5.0 redeployment of webapps takes a bit longer than you'd expect - in fact I noticed the TomcatDeployment mechanism undeploying/deploying my webapp three times before it finally stabilized, at which point page reloads will succeed without the misleading IllegalStateException.
  5. JBoss 5.1 redeployment goes by much faster; TomcatDeployment undeploys my webapp only once.

Thursday, May 14, 2009

Problem with ports-03 binding in JBoss 4.2

If you're setting up multiple instances of JBoss 4.2.x, you might run into this problem with the 3rd alternate configuration (ports-03).

There's a good writeup here for guidance on setting up multiple instances; I won't go into the motivation for doing it, let alone any details around how to do it here. I'll just assume you're reading this because you already know what I'm talking about - the topic at hand is already esoteric enough to require some prior knowledge, and I'd like to keep this post short.

When I set up a process to use the ports-03 binding, error messages appeared on deployment stating "Address already in use" for port 4446. Examining the binding-manager.xml file, I found that the service-config section that should override that default port was missing - and since my process using the default bindings was already running, the port conflict happened. Fix this by adding a copy of the "remoting connector" service-config section to the ports-03 configuration, changing the port to (e.g.) 7446, restart...and now you'll find that port 3873 has the same problem. Fix this by adding a copy of the "EJB3 Remoting Connector" section, changing the port to (e.g.) 4173, restart and you should be good to go.

Wednesday, May 13, 2009

JSF Cheatsheet

Here's a collection of various idioms, patterns, tips, and etc. around JSF 1.2. It's a work in progress that I'll be adding to over time. So far, it's compiled by pulling stuff from the following websites - and I thank each of the authors for my reproduction of their content here:

Preso by Ed Burns:
https://javaserverfaces.dev.java.net/presentations/demystifyingjsf.pdf

Tutorial from IBM (requires registration but is worth the hassle):
https://www6.software.ibm.com/developerworks/education/j-jsf1/section7.html

JSF Anti-Patterns and Pitfalls
http://www.theserverside.com/tt/knowledgecenter-is/knowledgecenter-is.tss?l=JSFAnti-PatternsandPitfalls

Java EE 5 Tutorial
http://java.sun.com/javaee/5/docs/tutorial/doc/bnaph.html

Declare Faces Servlet in web.xml:
<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet> 
 
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

JSF Configuration File

If you name your Faces configuration file faces-config.xml and place it in your Web application's WEB-INF directory, then the Faces Servlet picks it up and uses it automatically (because it's the default). Alternatively, you can load one or more application-configuration files through an initialization parameter — javax.faces.application.CONFIG_FILES — in your web.xml file with a comma-separated list of files as the body. You will likely use the second approach for all but the simplest JSF applications (but be sure to not list faces-config.xml in that initialization parameter, or any registered phase listeners will fire twice).

Sample JSF config file:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
version="1.2">
  <managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>com.mydomain.MyBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>
</faces-config>
JSF configuration files are specified via the javax.faces.CONFIG_FILES context parameter in web.xml:

<context-param>
  <description>comma separated list of JSF conf files</description>
  <param-name>javax.faces.CONFIG_FILES</param-name>
  <param-value>
    /WEB-INF/menu-config.xml,
    /WEB-INF/services-config.xml
  </param-value>
</context-param>
Again: do not specify faces-config.xml in this context-param -- if you do, any registered phases listeners will fire twice.


Declare standard JSF tags:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
The html taglib contains all the tags for dealing with forms and other HTML-specific items. The core taglib contains all the logic, validation, controller, and other tags specific to JSF.

An <h:panelGrid> can contain only components, whereas <h:form>, <f:view> and <h:panelgroup> can contain both HTML and components.

Import stylesheets:

<head>
  <title>My Application</title>
  <link rel="stylesheet" type="text/css"
    href="<%=request.getContextPath()%>/css/styles.css" />
</head>

User-Facing Messages

Customize messages (this approach does not scale, since it must be repeated for each section needing it):

<%-- case by case basis; message appears immediately to right of field --%>
<h:outputLabel value="Zip Code" for="zipcode" />
<h:inputText id="zipcode" label="Zip Code"
  value="#{myBean.zipcode}" required="true"
  requiredMessage="required" converterMessage="not a valid zip code"/>
<h:message for="zipcode" />
Change messages globally (this scales well, can be overridden as needed using case-by-case approach):

  • Add this tag to beginning of JSF config file(s):
<application>
  <message-bundle>mymessages</message-bundle>
</application>
  • Add entries to mymessages.properties resource bundle:
javax.faces.component.UIInput.REQUIRED_detail=value is required
javax.faces.converter.IntegerConverter.INTEGER_detail=that's not a valid integer
The complete list of default messages are found in the JSF 1.2 RI jarfile jsf-impl.jar, under javax.faces.Messages.properties.

In case the standard error messages don’t meet your needs, create new ones in resource bundles and configure the resource bundles in your application configuration resource file. For example, this message is stored in the resource bundle, MyMessages.properties:

invalidZipCode=The value you entered is not a zip code.

The resource bundle is configured in the application configuration file:

<application>
  <resource-bundle>
    <base-name>com.mydomain.MyMessages</base-name>
    <var>msgs</var>
  </resource-bundle>
</application>
The base-name element indicates the fully-qualified name of the resource bundle. The var element indicates the name by which page authors refer to the resource bundle with the expression language:

<h:inputText id="zipcode" label="Zip Code"
  value="#{myBean.zipcode}" converterMessage="#{msgs.invalidZipCode}">
...
</h:inputText>
Add messages to be displayed based on outcomes in server-side processing:

<h:messages infoClass="infoClass" errorClass="errorClass"
  layout="table" globalOnly="true"/>
....
<h:inputText id="minimum" label="Minimum"
  value="#{myBean.modelObject.minimum}" required="true"
  binding="#{myBean.minimum}" />
<h:message for="minimum" errorClass="errorClass"/>
....

acesContext facesContext = FacesContext.getCurrentInstance();
try {
...
  facesContext.addMessage(null, new FacesMessage(
    FacesMessage.SEVERITY_INFO, "Completed successfully", null));
...
} catch (Exception ex) {
  facesContext.addMessage(null,
    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), null));
...
} 

Adjust styles dynamically

<h:outputLabel value="Minimum" for="minimum"
  styleClass="#{myBean.minimumStyleClass}"/>
......
public String getMinimumStyleClass() {
  if (minimum.isValid()) {
    return "labelClass";
  } else {
    return "errorClass";
  }
} 

Access Component from Java

Factor out logic from JSP into managed bean (bind component to managed bean; lets you manipulate the component's state programatically without traversing the component tree to get to the component):

<h:panelGroup binding="#{myBean.panel}" rendered="false">
.......
private UIPanel panel;
public UIPanel getPanel() {
  return panel;
}

public void setPanel(UIPanel panel) {
  this.panel = panel;
}

public String execute() {
...
  try {
    modelObject.doSomething();
    panel.setRendered(true);
...
  } catch (Exception ex) {
...
    panel.setRendered(false);
  }
  return null;
} 

Injection into managed beans:

Using standard JSF Inversion of Control configuration:

<managed-bean>
  <managed-bean-name>myBean</managed-bean-name>
  <managed-bean-class>
    com.myDomain.MyBean
  </managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>modelObject</property-name>
    <value>#{modelObject}</value>
  </managed-property>
</managed-bean>
<managed-bean>
  <managed-bean-name>modelObject</managed-bean-name>
  <managed-bean-class>
    com.myDomain.MyModel
  </managed-bean-class>
  <managed-bean-scope>none</managed-bean-scope>
</managed-bean>
If you need to explicitly manage the order in which properties are set:

  • The specification states that a JSF implementation must inject the dependencies of a managed bean in the order in which they are configured
  • Applications that are using JSF 1.2 can take advantage of the PostConstruct annotation. Below, the PostConstruct annotation instructs the JSF implementation to invoke the initialize method after the managed bean has been created.
private ModelAttrs min, max; // injected
    // no setters and getters for min, max
  @javax.annotation.PostConstruct
  public void initialize() {
    if(min == null || max == null) {
      throw new NullPointerException("init failed - min or max is null");
    }
    if(min > max)) {
      throw new IllegalStateException("min cannot be larger than max");
    }
  }
However, it's still possible to call the no-arg constructor from somewhere other than the JSF framework, so this is not bulletproof.


  • Use a full blown dependency injection framework. Using Spring is as easy as placing the following lines of code in your JSF deployment descriptor.
<application>
  <variable-resolver>
    org.springframework.web.jsf.DelegatingVariableResolver
  </variable-resolver>
</application>
A JSF implementation is not required to warn you about misspelled class names or cyclical references in managed bean declarations at startup, but both will result in a runtime exception. JSF 1.2 will warn you about duplicate managed bean declarations but 1.1 will not.

Use JSFUnit to help address these types of problems (although I've yet to try it, so I'm unclear about the status of JSFUnit static analysis features, but it appears that the runtime testing is GA). You can also avoid some of these problems with annotations libraries found in Seam or Shale.




Navigation

Navigate via comandLink and navigation rule -from *any* view - URL in browser doesn't change (can't bookmark):

<navigation-rule>
  <from-view-id>*</from-view-id>
  <navigation-case>
    <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
  </navigation-case>
</navigation-rule>
...
<h:commandLink action="services" value="Go To Services"/>
More specific but still a generic "from-view" configuration:

<navigation-rule>
  <from-view-id>/pages/*</from-view-id>
  <navigation-case>
    <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
  </navigation-case>
</navigation-rule>
Navigation with change to URL in browser address bar:

<navigation-rule>
  <navigation-case>
  <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
    <redirect/>
  </navigation-case>
</navigation-rule>
Navigate directly (considered an antipattern: does not go through controller, thus no opportunity to initialize the model, etc.)

<h:outputLink value="pages/services.jsp">
  <h:outputText value="Go To Services"/>
</h:outputLink>

EL implicit objects

These give access to web scopes and more: cookie, facesContext, header, headerValues, param, paramValues, request, requestScope, view, application, applicationScope, initParam, session, sessionScope.


Lifecycle

The Lifecycle dictates how an incoming request is handled and how a response is generated. Two "portions" of lifecycle are "execute" and "render", each of which has phases:

  • Execute
    • Finding the View on which to operate (Restore View - initialize new view or restore existing)
    • Allowing components to get their values (Apply Request Values; process events - if conversion errors (from request to local value of component), store message in FacesContext, goto Render Response; if immediate=true, then validation/conversion/event processing is done here)
    • Ensuring the values are converted and validated (Process Validations; if validation errors, store message in FacesContext and goto Render Response)
    • Updating the model (Update Model Values - apply component local values to corresponding server-side object properties; process events; if conversion errors, goto Render Response)
    • Invoke Application - handle application-level events, e.g. submit a form, link to a page, etc.
  • Render
    • process events from Invoke Application phase
    • Selecting and rendering the new view (Render Response)
process events: Ensure any event listeners are called - can declare Response Complete to short-circuit lifecycle. For example, an application might need to redirect to a different web application resource, such as a web service, or generate a response that does not contain JavaServer Faces components. In these situations, the developer must skip the rendering phase by calling FacesContext.responseComplete.

When the life cycle handles an initial request, it only executes the restore view and render response phases because there is no user input or actions to process. Conversely, when the life cycle handles a postback, it executes all of the phases.

You can install PhaseListeners into the Lifecycle to do whatever you want before or after each or every phase. PhaseListeners are registered in a JSF configuration file:

<lifecycle>
  <phase-listener>com.myDomain.MyPhaseListener</phase-listener>
</lifecycle>
Each PhaseListener is global to the application and it subscribes to at least one phase event for every request, thus it is NOT thread-safe.



Event Handlers
  • Action Listeners use the observer pattern - they listen for events on a component (clicked, scrolled, etc). Accept one ActionEvent arg, return void.
  • Value Change Listeners listen for events around component value being changed. Accept one ValueChangeEvent arg, return void.
  • Actions return navigation outcomes. Accept zero-args, return String.

Steps in developing a JSF application
  • Create development directory structure
    • typical webapp layout
    • need JSF 1.2 jars
  • Create config files
    • web.xml
      • add servlet/servlet mapping for Faces Servlet
      • add context-param elements as needed
    • JSF configuration file(s) (a single faces-config.xml by default)
      • nav rules, managed beans, etc.
      • declare custom message.properties file for user-facing messaging
      • create many smaller config files vs one large one, partitioned as appropriate
    • messages.properties
      • override standard JSF messages as needed
  • JSF-specific steps
    • create pages
    • JSF tags: event handlers, validators, converters, messaging, etc.
    • define navigation
    • develop managed beans
    • provide properties, handle events, delegate to business classes, navigation logic
    • Tip: aggregate multiple models into a single managed bean (via compose-and-delegate) to present a facade to JSP
  • Add managed bean declarations
  • Build, deploy, and test the application
  • Iterate on JSF-specific steps and build/deploy/test

Thread Safety
The component will get a new Converter instance each time it is needed when you register a Converter and use a converter tag, thus this is a thread-safe approach:

<converter>
  <converter-id>myConverter</converter-id>
  <converter-class>com.myDomain.myConverter</converter-class>
</converter>

<h:inputText value="#{managedBean.value}" >
  <f:converter converterId="myConverter" >
</h:inputText>  
Using the converter attribute however could introduce a race condition because it is possible the same Converter instance will be used simultaneously by more than one request.

<managed-bean>
  <managed-bean-name>myConverter</managed-bean-name>
  <managed-bean-class>com.myDomain.myConverter</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<h:inputText value="#{myBean.value}" converter="#{myConverter}" /> 
Custom Validators have the same thread safety constraints as custom Converters.


View-State Encryption

By default, view state will not be encrypted. However, there is a way to do this with Mojarra. Specify a environment entry like so:

<env-entry>
  <env-entry-name>ClientStateSavingPassword</env-entry-name>
  <env-entry-type>java.lang.String</env-entry-type>
  <env-entry-value>[SOME VALUE]</env-entry-value>
</env-entry>
The presence of this JNDI entry will cause the state to be encrypted using the specified password...this isn't the most secure way of conveying a password, however, this cannot be accessed easily without having code executed on the server side.


Monday, May 11, 2009

Some notes on a JSF-related fix

It's late on a Friday and I've just solved a JSF headache, so I'm going to quickly write this up while it's still fresh in my mind (the solution, not the headache).

You may have stumbled onto this message if you're developing in JSF or just vanilla JSP:

#{..} is not allowed in template text

When you Google this phrase, you'll find various chunks of advice around versions of JSP, deferred expressions and the Unified Expression Language that comes with JSP 2.1. In particular, this reference appeared to have the definitive fix for my problem: either change the "#{" to "${", or backslash-escape the "#{" sequence, or change a setting to allow deferred syntax as literal. Now, any or all of these solutions might work for you, depending on your context; but I write this up because none of them worked for me.

What I have is a web application developed with JSF 1.1 that had used JSTL 1.1, but that then got deployed into a Java EE 5 environment which provides JSF 1.2 and JSTL 1.2. Many of you already know where this is going. But for my own future reference and possibly your amusement, I'm going to write it up anyway.

I changed all occurrences of #{ to ${, and knowing that Java EE 5 servers already supply the correct JSTL 1.2 version, I removed my webapp's private copies of jstl.jar and standard.jar (vestiges from when they were needed, with J2EE 1.4 servers), but now I get this error message:

According to TLD or attribute directive in tag file, attribute rendered does not accept any expressions

So the syntax change was a head-fake, at least in my case; I can't explain why. You are invited to chime in if you understand it. I was referred to one useful discussion that contains various suggested solutions and references various other threads, and it got me on the right track. Here's what I ended up doing: first, change the ${ back to #{, since really getting the incorrect JSTL version out of the way is the true fix. There is also an EL expression factory workaround discussed in that thread which was applied to my deployment descriptor.

But, here's where it gets interesting (as if it isn't already drop-dead compelling, right?) -- although removing the JSTL 1.1 stuff, applying the DD workaround and reverting back to #{ syntax should have cured all my problems, now I get an EL parsing error concerning this particular attribute construction:

text="#dds.value.enabled?isnsMsg.deactivate_action:isnsMsg.activate_action}"

This is a boolean expression managing a text value that must change depending on the state of a given backing bean property; this had worked just fine in my JSF 1.1 deployment, but now it's no good. The error reads something like this:

Was expecting one of:
"(" ...
<identifier> ...
<namespace> <identifier> "(" ...
Without belaboring the point - since I have a headache from all the different things I tried - I'll just admit it: I took the inelegant way out and used two panel-grouping blocks, each with its own rendered-if attribute, to fix this problem (I'm using tags from the Woodstock JSF component set):
<ui:panelGroup rendered="#{dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.deactivate_action}"/>
</ui:panelGroup>
                                       
<ui:panelGroup rendered="#{!dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.activate_action}"/>
</ui:panelGroup>
Using JSTL IF and WHEN testing is just as ugly, but at least it fails to work. The JSTL expressions get evaluated too soon relative to the JSF lifecycle, i.e. the IF and WHEN always yield false since they're evaluated before the backing bean property gets its value set as needed.

I didn't do any research to understand why the inline boolean expression in JSF 1.1 caused a parsing error in JSF 1.2 (or maybe it's a JSP 1.2 vs JSP 2.0 thing...hey, probably it's JSTL 1.1 vs 1.2...isn't web-tier fun?). So while I've solved the immediate problem, I've left plenty of room for colleagues to elaborate and, frankly, to correct me where I'm misleading. Like I say, it's late on a Friday and sometimes I do as little as necessary to get from A to Z. If anyone has additional insights around what's discussed here, you are invited to share.