Posts Tagged RichFaces

Close ModalPanel if no error

It has been a very long time I wrote this code, but I thought I would share it with you as it is quite useful.

If like me, you are an adept of RichFaces, you might have already seen and used the modal panel functionality. By default, a modal panel is used to display a message, but what if you actually want to display a form within it? How nice would it be if, for example, you could put your login form in a modal panel instead of opening a new page?

With the following steps, you will be able to achieve this:

  • First, get the maximum severity in the message queue:
    <a4j:outputPanel ajaxRendered="true">
        <h:form style="display:none" id="maximumSeverityForm">
            <h:inputHidden id="maximumSeverity"
                value="#{facesContext.maximumSeverity.ordinal}"/>
        </h:form>
    </a4j:outputPanel>
    

    This form has to be placed on all your pages using an include for example. This form will basically get refreshed on every postback and will contain the maximum severity in the message queue or null if the queue is empty.

  • Create a JavaScript method which reads the maximumSeverity hidden field:
    function ajaxRequestContainsErrors() {
        return document.getElementById("maximumSeverityForm:maximumSeverity").value > 0;
    }
    

    This method has to also be included in all the pages.

  • Finally, use the following code for the “Submit” button in your form:
    <a4j:commandButton action="#{userBean.loginAction}" value="Submit" oncomplete="if (!ajaxRequestContainsErrors()) {Richfaces.hideModalPanel('loginModalPanel');}"/>
    

    This button is actually checking if there is no error before closing the modal panel.

, , ,

No Comments

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

, , , , ,

No Comments

The selfRendered attribute

This is an interesting problem related to the RichFaces rich:suggestionbox tag.

Let’s take the following code:

<rich:suggestionbox for="q" minChars="1"
    suggestionAction="#{myBean.mySuggestionAction}" var="result"
    limitToList="true">
    <h:column>
        <h:outputText value="#{result}" />
    </h:column>
</rich:suggestionbox>

If you use the code above as it is, the whole page is going to be processed each time the suggestionAction is called. And because the minChars attribute is set to 1, the action is going to be called each time the user enters a character! ๐Ÿ˜ฎ
For obvious reason, such as performance issue, this is not ideal.

To avoid this behaviour, you simply need to set the attribute selfRendered to true as shown below:

<rich:suggestionbox for="q" minChars="1"
    suggestionAction="#{myBean.mySuggestionAction}" var="result"
    limitToList="true" selfRendered="true">
    <h:column>
        <h:outputText value="#{result}" />
    </h:column>
</rich:suggestionbox>

Here is the description of the selfRendered attribute from RichFaces documentation:

If “true”, forces active Ajax region render response directly from stored components tree, bypasses page processing. Can be used for increase performance. Also, must be set to ‘true’ inside iteration components, such as dataTable.

Don’t hesitate to add this attribute to increase the performance of your website. ๐Ÿ˜‰

, , ,

No Comments

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!‘. ๐Ÿ™‚

, , , ,

No Comments

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

, , , ,

No Comments