Thursday 4 April 2013

[Fact] - The order of calling for Action and Listener in JSF

During the coding process, sometimes, I still mix up the order that Action and ActionListener components would be triggered in JSF. In this small post, I will make a small experiment as a reminder to both you and me :).

Our test page will contain the following button:

And this is our test bean:

The following outcome was observed from the console:


At times, I tried in vain to set a property of the backing bean using <f:setPropertyActionListener> and get it out in the method inside actionListener. Don't make the same mistake :P!

From the above outcome, the actionListener attribute of the button is always called first while the action attribute is always called last. For the others, they will be called based on the order in which you declare them inside the button.

Hope this helps! :)

Tuesday 2 April 2013

[How To] - Redirect to original page after login in JSF

Nowadays, redirecting users to where they were before logging is a common & desired feature for any web applications. For instance, if a user was surfing a page at http://example.com/yourapp/pageX.xhtml?param1=value1, the application should be able to redirect the user to the same page and, at the same time, retain the complete query string at the end of the requestURL.

In this tutorial, I will assume that your application has a login bar on top of all pages. Based on this assumption, your application needs to handle the following 3 scenarios:
  1. The user logs in directly from the top login bar and succeed.
  2. The user entered wrong password, etc.
  3. The user was forwarded or redirected to the login.xhtml page when they tried to access a restricted resource.
For the first scenario, one very important thing to note is that when a user clicks the Login button, the requestURL for that click will not carry the original query string anymore. As a consequence, if you capture the requestURL at this point, it's too late and you will only have http://example.com/yourapp/pageX.xhtml. In other words, to get the full requestURL, you need to capture the requestURL even before the user clicks the Login button. To achieve this goal, in your templates, you need to define the following <f:event>:

This is our  @SessionScoped managed bean:

And this is the Login managed bean:

For the second scenario, users will usually arrive at the login.xhtml page where you display a big & fat error message. At this point, you might have jumped into your own trap if you have also included the above <f:event> inside your login.xhtml page. The event would be triggered and your originalURL property would be wrongly updated to the login page's URL. So, in brief, you must NOT include the above <f:event> inside your login.xhtml page.

Done? No, this is a double-trap :O!  We still need to take care of the situation in which the user didn't surf any pages before logging in.

For the third scenario, you need to understand the difference between a forward and a redirect. When a user is forwarded to the login.xhtml page, the requestURL will still be http://example.com/yourapp/pageX.xhtml?param1=value1 even though the content of the view is from the login.xhtml page. On the other hand, if the user is redirected, the requestURL will become http://example.com/yourapp/login.xhtml.

In case the user was redirected, I will assume that you're using a homegrown Filter to perform the login check and redirect users afterward. In this situation, you need to include the original requestURL as a parameter in the redirecting URL:

After that, you need to update your LoginBean#init() function to retrieve the parameter in both cases as following:

Finally, after spilling much sweat, you can enjoy your work now! :)