Posts Tagged JSF
Delete the components holding unwanted state
This is a small addition to a problem discussed on the MyFaces Wiki: http://wiki.apache.org/myfaces/ClearInputComponents
Just in case the page is removed from the Wiki, please see below a copy of the problem description:
Sometimes you want to provide a command component (eg a link or button) that performs some server action, and renders the same page but with completely “fresh” values for all components.
When using command components with the normal immediate setting (false), achieving this is just a matter of clearing the beans that the JSF component value attributes access. Any values entered by the user will have been pushed into these beans as part of the Update Model phase, so the components themselves will not be holding any information about submitted data. The action method associated with the command is then run which resets the model, and when the components render themselves they will draw fresh data from the (reset) beans.
Note that because data is being pushed into the model, the validation phase must run, and therefore any invalid data in the page will cause the action to be skipped, and the page is redisplayed with the validation errors displayed. This is not generally the desired behaviour for a “clear” type operation! The solution is to set attribute immediate=true on the command so that its associated action is invoked before validation is applied to the input components in the same view (see How_The_Immediate_Attribute_Works).
However when using command components with immediate=true, things become more complex. All components will retrieve the raw submitted values submitted by the user, but the immediate command will then run before they can be pushed into the backing beans; the components therefore remember this data. When the (immediate) action causes navigation to another view then this is no problem; these components will be discarded anyway. However if the action method causes JSF to go directly to the render phase ‘of the same view’ [by calling facesContext.renderResponse()], then the components will behave as they do for a validation failure – by displaying the value cached in the component rather than fetching data from the backing bean.
MyFaces gave four solutions to this problem, but the one I used is the following:
Find the parent component of the problem inputs, and call
parentComponent.getChildren().clear();
During the render phase, new instances of these child components will then be created, while other components will not be affected.
This is effectively the same as the above solution, but discards a selected subset of components rather than the UI!ViewRoot.
Obtaining the parent component to discard can be done via binding. Alternatively, the “action listener” form of callback can be used for the command; this is passed an ActionEvent from which the command component that was clicked can be found. A call to “findComponent” can be made on this to locate the desired parent component by id, or other similar solutions.
All of this is good and well but what if you don’t have the component object but only the name of the form? How would you call the clear
method then?
This is the reason why I wrote the code below:
/** * Return the UIComponent that represents the root of the UIComponent tree. * @return the UIComponent that represents the root of the UIComponent tree */ public static UIViewRoot getUIViewRoot() { FacesContext facesContext = FacesContext.getCurrentInstance(); return facesContext != null ? facesContext.getViewRoot() : null; } /** * Search for a component in the UIComponent tree * @param parentComponent the parent component * @param componentId the component identifier we look for * @return the component found */ private static UIComponent findComponent(UIComponent parentComponent, String componentId) { if (parentComponent != null) { if (componentId.equals(parentComponent.getId())) { return parentComponent; } for (UIComponent child : parentComponent.getChildren()) { UIComponent component = findComponent(child, componentId); if (component != null) { return component; } } } return null; } /** * Deletes components holding unwanted state * @param componentId the component identifier */ public static void deleteComponentsHoldingUnwantedState(UIComponent parentComponent) { if (parentComponent != null) { parentComponent.getChildren().clear(); } } /** * Deletes components holding unwanted state * @param componentId the component identifier */ public static void deleteComponentsHoldingUnwantedState(String componentId) { deleteComponentsHoldingUnwantedState(findComponent(getUIViewRoot(), componentId)); }
The last method of the code above will allow you to delete all the components holding unwanted state of a form simply by passing its name.
For example:
deleteComponentsHoldingUnwantedState("myform");
Upgrade to RichFaces 3.3.3.Final
From time to time, it is good to upgrade the application libraries to the latest stable version. Especially the frontend libraries as the browsers are constantly involving and new ones are coming on the market.
This is why I wanted to upgrade the RichFaces library on one of my web application which was still using the version 3.3.0.GA with JSF/MyFaces 1.2.5.
The RichFaces dependency was looking like the following in my pom.xml
file:
<dependency> <groupId>org.richfaces.ui</groupId> <artifactId>richfaces-ui</artifactId> <version>3.3.0.GA</version> <scope>compile</scope> </dependency>
The upgrade should be straightforward.
But when changing to the version 3.3.3.Final, I got the following error:
2010-10-13 15:56:14.959::WARN: Error starting handlers java.lang.NoClassDefFoundError: org/ajax4jsf/component/SequenceDataAdaptor at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632) at java.lang.ClassLoader.defineClass(ClassLoader.java:616) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at java.net.URLClassLoader.access$000(URLClassLoader.java:58) at java.net.URLClassLoader$1.run(URLClassLoader.java:197) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:366) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632) at java.lang.ClassLoader.defineClass(ClassLoader.java:616) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at java.net.URLClassLoader.access$000(URLClassLoader.java:58) at java.net.URLClassLoader$1.run(URLClassLoader.java:197) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:366) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632) at java.lang.ClassLoader.defineClass(ClassLoader.java:616) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) at java.net.URLClassLoader.access$000(URLClassLoader.java:58) at java.net.URLClassLoader$1.run(URLClassLoader.java:197) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:366) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:247) at org.apache.myfaces.shared_impl.util.ClassUtils.classForName(ClassUtils.java:132) at org.apache.myfaces.shared_impl.util.ClassUtils.simpleClassForName(ClassUtils.java:158) at org.apache.myfaces.application.ApplicationImpl.addComponent(ApplicationImpl.java:564) at org.apache.myfaces.config.FacesConfigurator.configureApplication(FacesConfigurator.java:650) at org.apache.myfaces.config.FacesConfigurator.configure(FacesConfigurator.java:277) at org.apache.myfaces.webapp.AbstractFacesInitializer.buildConfiguration(AbstractFacesInitializer.java:131) at org.apache.myfaces.webapp.Jsp21FacesInitializer.initContainerIntegration(Jsp21FacesInitializer.java:64) at org.apache.myfaces.webapp.AbstractFacesInitializer.initFaces(AbstractFacesInitializer.java:83) at org.apache.myfaces.webapp.StartupServletContextListener.contextInitialized(StartupServletContextListener.java:72) at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:540) at org.mortbay.jetty.servlet.Context.startContext(Context.java:135) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220) at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:510) at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448) at org.mortbay.jetty.plugin.Jetty6PluginWebAppContext.doStart(Jetty6PluginWebAppContext.java:110) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152) at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:117) at org.mortbay.jetty.Server.doStart(Server.java:222) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) at org.mortbay.jetty.plugin.Jetty6PluginServer.start(Jetty6PluginServer.java:132) at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:357) at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:293) at org.mortbay.jetty.plugin.AbstractJettyRunMojo.execute(AbstractJettyRunMojo.java:203) at org.mortbay.jetty.plugin.Jetty6RunMojo.execute(Jetty6RunMojo.java:182) at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:451) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(DefaultLifecycleExecutor.java:558) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeStandaloneGoal(DefaultLifecycleExecutor.java:512) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(DefaultLifecycleExecutor.java:482) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:330) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:291) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:142) at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129) at org.apache.maven.cli.MavenCli.main(MavenCli.java:287) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315) at org.codehaus.classworlds.Launcher.launch(Launcher.java:255) at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430) at org.codehaus.classworlds.Launcher.main(Launcher.java:375) Caused by: java.lang.ClassNotFoundException: org.ajax4jsf.component.SequenceDataAdaptor at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at org.codehaus.classworlds.RealmClassLoader.loadClassDirect(RealmClassLoader.java:195) at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:255) at org.codehaus.classworlds.DefaultClassRealm.loadClass(DefaultClassRealm.java:274) at org.codehaus.classworlds.RealmClassLoader.loadClass(RealmClassLoader.java:214) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:375) at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337) ... 82 more
What happened here? I simply changed the version number and it now does NOT work! ๐
Looking at the exception, it seems that it cannot find the class org.ajax4jsf.component.SequenceDataAdaptor
which is part of the richfaces-impl
library. Why not?
Well, in fact, it is quite simple! It appears that from the version 3.3.3 of RichFaces, you now have to specifically add the richfaces-impl
dependency to your pom.xml
file such as:
<dependency> <groupId>org.richfaces.ui</groupId> <artifactId>richfaces-ui</artifactId> <version>3.3.3.Final</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.richfaces.framework</groupId> <artifactId>richfaces-impl</artifactId> <version>3.3.3.Final</version> <scope>compile</scope> </dependency>
Why do we have to manually add this dependency? This is because the new version of RichFaces allows you to use JSF 2.0 instead of JSF 1.2. To do that, simply add the library richfaces-impl-jsf2
instead of richfaces-impl
in your pom.xml
file.
Please click on the following link for the JBoss manual about this configuration:
http://community.jboss.org/wiki/HowtoaddRichFaces33xtomavenbasedproject
loadBundle’s behaviour with JSTL tags
Let’s start with a bit of knowledge.
f:loadBundle
is a JSF tag which loads a resource bundle and saves it as a variable in the request scope. The RichFaces a4j:loadBundle
tag is a substitution for the f:loadBundle
tag and allows to use reference to bundle messages during the Ajax re-rendering.
When I discovered the RichFaces tag, I immediately replaced all the f:loadBundle
tags by a4j:loadBundle
. Was I right? I thought at first, but then I got a problem. ๐
The problem was appearing when I started mixing RichFaces and JSF tags.
For example, let’s take the following resource bundle:
active=true
And the following code:
<a4j:loadBundle basename="Messages" var="msg" /> Active is #{msg.active} -- <c:if test="#{msg.active}"> Hello World! </c:if>
This displays ‘Active is true --
‘.
What is wrong there? The active message is true but the c:if
condition failed! ๐ฏ
Let’s now try the following:
<a4j:loadBundle basename="Messages" var="msg" /> Active is #{msg.active} -- <c:if test="#{empty msg.active}"> Hello World! </c:if>
This displays ‘Active is true -- Hello World!
‘.
What does that mean? It seems that JSTL doesn’t get the value of the active
message but gets an empty string instead!
In conclusion, if the resource bundle is loading using the RichFaces tag, the messages will be not visible by the JSTL tags.
To fix this problem, you will have to also load the resource bundle using the JSF tag:
<a4j:loadBundle basename="Messages" var="msg" /> <f:loadBundle basename="Messages" var="msg" /> Active is #{msg.active} -- <c:if test="#{msg.active}"> Hello World! </c:if>
As expected, this displays ‘Active is true -- Hello World!
‘. ๐
Clock change affecting date display
This is a very particular problem which happens only during the summer and not even in all the countries ! ๐ฎ
The problem is related to the Daylight Saving Time (DST), also called British Summer Time (BST):
Daylight saving time is the practice of temporarily advancing clocks so that afternoons have more daylight and mornings have less. Typically clocks are adjusted forward one hour near the start of spring and are adjusted backward in autumn.
Okay, so how do we display dates with JSF?
Let’s take this can’t-be-simpler bean:
public class MyBean { public Date getDate() { return new Date(); } }
And let’s insert the following code in a JSF page:
#{myBean.date}
The result is Fri Sep 17 20:03:14 BST 2010
(when I wrote this article).
If I check my clock, the date and time above are correct.
So far so good. ๐
Let’s now use the h:outputText
tag from JSF:
<h:outputText value="#{myBean.date}"/>
The result is Sep 17, 2010
.
Alright, the date is correct but the time is not displayed…
Let’s use the f:convertDateTime
tag to also display the time:
<h:outputText value="#{myBean.date}"> <f:convertDateTime pattern="E MMM dd HH:mm:ss z yyyy" /> </h:outputText>
The result is Fri Sep 17 19:03:14 GMT 2010
.
What can we see here? The time went one hour backward!
Why that? well, simply because the date is now displayed in GMT, instead of BST earlier.
So, this means that the h:outputText
tag is displaying the date in GMT by default, which would be fine in winter but not in summer.
In order to fix this behaviour, you need to add the attribute timeZone
to the f:convertDateTime
tag such as:
<h:outputText value="#{myBean.date}"> <f:convertDateTime pattern="E MMM dd HH:mm:ss z yyyy" timeZone="GB" /> </h:outputText>
Note that if you put BST
instead of GB
in the timeZone
attribute, the time zone is going to be actually set to BDST which stands for Bangladesh Daylight Saving Time! ๐
How to configure JSF to get the browser Back button working
Lately, I had a problem with one of my JSF applications which is using RichFaces.
The problem was happening when the user was hitting the browser Back button. Well, you would say that it is a usual problem in web development. But still, because we cannot disable the browser Back button, the web application needs to work fine if the user decides to click on it!
Anyway, let’s get back on topic. As I said, the problem occurred if the user was clicking on the Back button but the funniest thing is it was happening when he was clicking twice on it! Why did it work fine when clicking once but not twice? ๐ฎ
The solution is quite simple actually.
It was coming from one of the options in MyFaces configuration: com.sun.faces.numberOfViewsInSession
.
Here is a quick explanation of this option:
com.sun.faces.numberOfViewsInSession
Specifies the number of views that are stored in the session when Server-Side State Saving is used. If set to true while client-side state saving is being used, reduces the number of bytes sent to the client by compressing the state before it is encoded and written as a hidden field. The default for this parameter is 15.
So basically, JSF is storing each page previously viewed by the user in session. And, as you can see from the description above, JSF will stored a maximum of 15 pages by default. However, it was set to 1 in my application, which means only ONE page would be stored…
This was obviously the reason why the application was working fine if the user was clicking only once on the Back button but not twice! ๐
For the same reason, you should also check the option org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION
which is default to 20:
org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION
Defines the number of the latest views that are stored in session. This option is only applicable if the state saving method is set to server. The default for this parameter is 20.
For more information about JSF options, please have a look at the following page:
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/rweb_jsfengine.html