JSF Central - Using the RichFaces Queue
JSF Central

 
 Home 
 
 Products 
 
 Articles & Books 
 
 Resources 
Using the RichFaces Queue
 
Using the RichFaces Queue
by Max Katz
28 Jun 2010 1:00 EDT

This article shows you how to control traffic to the server using the RichFaces queue.


RichFaces is a rich framework for JSF. RichFaces consists of three main parts:

  1. Two tag libraries (a4j: and rich:) that offer over 100 rich and Ajax enabled JSF components
  2. Skins and themes
  3. Component Development Kit (CDK) - a set of tools for quickly creating custom rich components
  4.  

RichFaces is hosted on jboss.org and being developed by the Exadel team. You can view RichFaces components demo here.

RichFaces Versions and Compatibility

RichFaces 3.3.2 works with JSF 1.2.
RichFaces 3.3.3 works with both JSF 1.2 and 2. Read more about JSF 2 support here.
RichFaces 4 is based on JSF 2. At the time of writing of this article (May 2010), RichFaces 4 is in active development. You can read more about it here, and download the latest milestone here.
If you already used JSF 2, then you are probably familiar with f:ajax tag. This tag allows you to add Ajax functionality to any other UI component. This tag is very similar in how it works to the RichFaces a4j:support tag. In fact, f:ajax was greatly inspired by the RichFaces a4j:support tag. In RichFaces 4, a4j:support tag is going to be renamed to a4j:ajax to better match the standard tag name. Why does RichFaces even need this tag anymore? f:ajax offers rather basic Ajax support; RichFaces a4j:ajax will be using f:ajax behind the scenes, but will add more flexibility, customization, and advanced features on top of the standard tag that you get today in version 3.x.

When building an Ajax application in JSF, one of the things you need to consider is how to control traffic to the server. Although Ajax applications make the application richer, quicker, and more interactive, in many instances the end user is not aware that the client (browser) is sending Ajax requests to the server. For example, if an input field fires an Ajax event on the onkeyup event, the user can easily flood the server with to many requests without even knowing it. This is also true of a regular button that fires an Ajax request. In a traditional (non-Ajax) application, the user is more aware that a request was sent. In such an application, the browser window could go blank for a fraction of a second while the next page is loaded. In other words, there is visual clue that page was submitted. But if the button fires an Ajax request, the page is not reloaded. The user could be clicking the button every second and not realizing that he or she is firing new requests each time. If multiple requests are fired almost at the same time, there is no guarantee they will be processed in the same order without any additional work on the server.

The developer should be able to control how much traffic and how many requests the client fires or the server processes.

RichFaces offers a whole set of features for controlling traffic to the server via its a4j:queue tag, which I’m going to show you next.

The basic queue usage

There are a number of ways to configure the queue, such as per form (h:form) or per view. I’m going to come back to configuration in the second half of this article. The concepts that we are going to cover next are the same no matter which way the queue is configured.

The moment you place a4j:queue on a page without any attribute, you already get a lot of functionality. Let’s take a very simple application to demonstrate these features. As a new color is selected, the background of the RichFaces label will be updated accordingly. An Ajax request is sent via a4j:support on the onkeyup event (using the keyboard). Figure 1 shows a screen shot, followed by the JSF page and bean code:

  Figure 1: The page we are going to use in examples
Figure 1: The page we are going to use in examples

Note: if you want to run this application, here is a quick way to start. Download this template for Eclipse.

The JSF page: <h:form> <h:panelGrid columns="2"> <h:selectOneListbox value="#{colorsBean.color}"> <f:selectItem itemValue="green" itemLabel="Green" /> <f:selectItem itemValue="blue" itemLabel="Blue" /> <f:selectItem itemValue="red" itemLabel="Red" /> <f:selectItem itemValue="yellow" itemLabel="Yellow" /> <f:selectItem itemValue="orange" itemLabel="Orange" /> <f:selectItem itemValue="grey" itemLabel="Grey" /> <f:selectItem itemValue="pink" itemLabel="Pink" /> <a4j:support event="onkeyup" action="#{colorsBean.select}" reRender="colorPanel" /> </h:selectOneListbox> <h:panelGrid id="colorPanel" bgcolor="#{colorsBean.color}"> <h:outputText value="RichFaces" style="FONT-WEIGHT: bold; FONT-SIZE: xx-large;" /> </h:panelGrid> </h:panelGrid> </h:form>

The managed bean: public class ColorsBean { private String color; // getter and setter public void select (){ // do something } }

Run the page, put the cursor on the Green color and very quickly (using the down arrow) scroll through the values all the way to Pink. You should see the background quickly updating as you scroll. This make sense. Every time a new value is selected, a new request is sent. However, this is not the behavior you want, as it’s possible to flood the server with requests and set the wrong color. At the least, there should be a way to prevent this.

Let’s make a small change to the bean. We’ll add a small delay to the action method. Right now it doesn’t do anything, but in a real application an action could take a few second to execute. So, let’s add a 2-second delay: public class ColorsBean { private String color; // getter and setter public void select (){ // do something try { Thread.sleep (2000); } catch (InterruptedException e) { e.printStackTrace(); } } }

We can also add a status tag to the page to be able to see when an Ajax request is being executed. Just add this anywhere on a page, for example just before the form: <a4j:status id="stateStatus" startText="Working..." startStyle="background-color: #ffA500; font-weight:bold; position:absolute; right: 50%; top: 1px; width: 100px;" />

After adding a4j:status, any time an Ajax request is being executed, you will see Working... at the top (center) of the browser.

When you repeat the above steps, quickly scrolling through all the values, we get a very similar result. There is a slight delay after the first selection (the action method is being executed) and then the background changes quickly to different colors. Again, this is something we want to prevent, as we just sent many requests to the server.

Let’s add a4j:queue tag without any attributes. Place this tag before h:panelGrid tag: <a4j:queue/>

Run the page again. We now get a different result. Do this: Select Green. Now, using the down arrow select all the values, all the way to Pink. First the background is blue and then pink.

As a value is selected, a request is fired to the server. While the server is processing the request, if any value is selected again (Ajax request is fired), that request will be queued and will not be fired until the original request comes back.

In fact, you can select any number of colors and only the last will be sent.

As you can see, this is already a lot of functionality. Just setting the a4j:queue tag anywhere on the page will prevent the client (browser) from flooding the server with multiple requests from the same control (button).

Suppose we have a very impatient user and who decides to select many colors quickly. Because the same component fires all events (h:selectOneListbox), every new select (or event) will replace the currently queued event. This means that no matter how many times the user selects a new color, only one event will be fired. That’s what happens in our example:

  • The Blue event is fired.
  • All subsequent events are replaced by the following one. The last one queued is Pink.
  • Once the Blue request returns, Pink is fired and the background is updated with Pink.

This table shows the clicks, queue status, and server:

Event - color selection Queue Server
A1 [nothing] A1 is being processed for a few seconds
A2 A2 A1
A3 A3 (replaces A2) A1
A4 A4 (replaces A3) A1
A5 A5 (replaces A4) A1
A6 A6 (replaces A5) A1

If no new color is selected, once an A1 request comes back, A6 will be fired.

Setting a delay

It’s possible to set a delay on a queue as shown here: <a4j:queue requestDelay=”2000”/>

This means that when a color is selected, the event will be queued and will be fired only after two seconds. Another way to look at a delay is that it is the time to wait for new requests to be fired from the same component and for this new event to replace the one that has been queued. The following table shows a sequence of Ajax requests:

Event - color selection Queue (2 sec. delay) Server
A1 A1
A2 (within 2 sec.) A2 (replaces A1)
A3 (within 2 sec.) A3 (replaces A2)
A4 (after 4 sec.) A4 A3

For event A4 to be fired, two things need to happen. The previous request from the server has to finish and the A4 delay time has to pass.

Back to our example, select Green via a mouse-click. Using key down, select Blue, then Red, and stop at Yellow. The first request was queued due to the delay. Because within the delay a new value was selected, the original one was replaced, and so on. The final result is the background is yellow.

So far we only used one control (h:selectOneListbox). Let’s see what happens when you have two controls.

Queue with multiple controls

Putting our colors example aside for a second, let’s say we have these two buttons, shown in figure 2, that fire an Ajax request.

  Figure 2: The two buttons that fire an Ajax request
Figure 2: The two buttons that fire an Ajax request

Let’s use tables to demonstrate queue state and sequence of Ajax requests fired. Let’s also assume there is no delay on the client and it takes a few seconds for the request to be processed on the server.

Button click Queue Server
A1 A1
A2 A2 A1
A3 A3 (replaces A2) A1

So far so good. Let’s continue the table now by clicking the B button.

B1 B1 A3 A1
B2 B2 A3
A4 A4 B2 A3

Notice, because we now clicked Button B (B1), it’s a different control than button A. The B1 event cannot be combined or replace A1. This is because they are different controls (buttons). Now we have two events queued.

As we click button B again (B2), because the last request queued is from the B control (it’s the same control), we can replace it with B2.

If we now click button A again (A4), this event can not longer replace A3 (as there is B2 in the middle). Thus, A4 is simply queued after B2.

You should be able to see the pattern here. Events can be replaced only if the last event in the queue is from the same control as the new fired event (that the user just clicked).

Combining controls into the same group

In the above example, events can be replaced only if they are coming from the same control and the last event from the queue is from the same control. It’s possible to place two or more controls into the same “logical” group. In this setup, events can replace each other no matter which control in the group was activated.

All controls in RichFaces that can fire an Ajax request come with an attribute called similarityGroupingId. By default, this attribute is set to the component client Id. By default, every control is in its own group. Using this attribute, you can easily place any number of controls in the same group. For example: <a4j:commandButton value=”Button A” similarityGroupingId=”queueGroup”/> <a4j:commandButton value=”Button B” similarityGroupingId=”queueGroup”/>

We have two buttons, but from the queue’s perspective they are going to act as one logical control. Let’s go to our table to see what this means.

Button click Queue Server
A1 A1
A2 A2 A1
A3 A3 (replaces A2) A1
B1 B1 replaces (A3) A1
A4 A4 (replaces B1) A1
B2 B2 (replaces A4) A1

Now, no matter which button is clicked, the events always replace each because both buttons are in the same group via the similarityGroupingId attribute.

Ignoring a response

Let’s go back to our example. Before we continue, let’s remove the delay from the queue. After removing, it should look like this: <a4j:queue />

Let’s run it again. Select Green with the mouse. Then using the down arrow, select all the values, and stop at Pink. Blue is the first request that’s fired. All other requests are replaced by the next one until we stop at Pink. So, the result is that we see a Blue background and at the end we see a Pink background. Looking at this again, when the background changes to Blue, it’s likely that we are not interested in that color anymore. After all, we already selected a different one and stopped at Pink. There is an option in the queue to ignore or drop the request from updating the DOM if another request from the same component was queued. That’s our situation. Blue was fired, Pink was queued via the same component. We can ignore the DOM update when Blue response comes back. To do that we set the ignoreDupResponse attribute: <a4j:queue ignoreDupResponses="true"/>

When you run the page again, you will now only see a Pink background, as Blue is now ignored. It’s important to understand that the Blue event finished executing on the server. We can’t drop it on the server. When the Blue response comes back, we are simply not updating the DOM.

Another example can be a suggestion box-like component. Suppose you type “abc” and it takes the server a few seconds to send back the response. While the server is processing the request, you change your mind and type something completely different, for example “xyz.” It probably makes no sense anymore to display the result from “abc.” When the “abc” response comes back, you can ignore it and only display the “xyz” response. Again, keep in mind that the “abc” request finished executing on the server and just wasn’t processed on the client (browser).

Queue size

By default the queue size is unlimited. There are options to limit the queue size and then to do something when queue size is exceeded.

First, defining the queue size is done by setting the size attribute:

<a4j:queue size="3"/>

When you set the queue size to 3, only three requests will be queued before the size is exceeded. There are four actions that can be taken when the fourth request is fired. The four options are:

Action Description
dropNext Drops next request that should be fired, making room for new request
dropNew Drops the incoming request, the one that was just fired
fireNext Immediately fires the next request in the queue (first in line to be fired)
fireNew Immediately fires the incoming request, the one that was just fired

To take a particular action when the size is exceeded, the sizeExceededBehavior attribute is used:

<a4j:queue size="3" requestDelay="3000" sizeExceededBehavior="dropNext" onsizeexceeded="alert('The size of the queue is exceeded')" />

You can also use the onsizeexceeded JavaScript event to invoke a JavaScript or just notify the user, as above.

When limiting size, it’s possible to have two or more requests be processed on the server at the same time. For example, let’s say some request is being executed on the server. The queue size is set at 2 and they are already two requests queued and waiting for the first one to come back. If another component is activated, and the action to take when the queue size is exceeded is fireNew, then the new request will be immediate fired while the first one is still executing. This is something to keep in mind.

Defining a queue

Now that you know the basics of how to work with a queue, let’s look at the different ways to define them. There are a number of ways to create queues.

Named queue

A queue is given a name, and controls explicitly use this queue via its name: <a4j:queue name="someQueue"/> ... <a4j:commandButton eventsQueue="someQueue"/>

Any RichFaces component from either a4j: or rich: tag library that has an eventsQueue attribute can point to a named queue. For example: <rich:suggestionbox eventsQueue="someQueue"> ...</rich:suggestionbox> It's important to note that named queues are not pipelined; requests from such queues run in parallel. In other words, if there are two named queues and two different components use then, it's possible to have requests sent and processed at the same time.

Form-level queue

All controls inside the form will use this queue (unless some component references a named queue): <h:form> <a4j:queue /> // other controls </h:form>

View-level queue

All controls inside this view will use this queue (in Facelets you don’t need to explicitly define a view; the entire page is a view by default): <f:view> <a4j:queue /> // other controls </f:view>

Setting attributes

No matter which queue configuration you use, there are two ways to set attributes. One is to set attributes directly on a component that fires an Ajax request, for example: <a4j:commandButton value="Submit" eventsQueue="someQueue" requestDelay="30000" similarityGroupingId="ajaxGroupOne" ingoreDupResponses="true"/>

If you have multiple components that fire an Ajax request, instead of setting the same attributes on each component, you can set them directly on the queue tag. That’s the second way to set attributes, for example: <a4j:queue requestDelay="30000" similarityGroupingId="ajaxGroupOne" ingoreDupResponses="true"/>

As you can see, attributes can be set on the queue, but it's also possible to set attributes on the actual component firing the event, and component level attributes overwrite the queue level attributes.

Global queue

A global queue is used by all the pages in the application. A global queue is defined in the web.xml file: <context-param> <param-name>org.richfaces.queue.global.enabled</param-name> <param-value>true</param-value> </context-param>

The above is equivalent to adding the following to every page in your application: <a4j:queue name="org.richfaces.queue.global"/> The global queue name is org.richfaces.queue.global. To set attributes on the queue, we use the queue name like this: <a4j:queue name="org.richfaces.queue.global" requestDelay="3000"/>

Request delay will be set for the current page only.

If you need to disable the global on any particular page, then the disabled attribute can be used: <a4j:queue disabled="true" name="org.richfaces.queue.global"/>

I hope this articles has given you a good understanding of how the RichFaces queue works.

Summary

Ajax applications can be very chatty without the user being aware that numerous requests are being fired. For developers, it's important to be able to control how many Ajax requests are send to the server. Too many requests at the same time could flood the server and produce unpredicted results.

When using RichFaces, you get the sophisticated and feature-rich a4j:queue tag that allows you to easily to control traffic to the server. Although the tag comes with many advanced features, just placing the tag on the page (without any attributes) provides core functionality in controlling Ajax requests to the server

A very big thank you to Nick Belaevski and Ilya Shaikovsky both from Exadel RichFaces team for doing the technical review.

Resources



RSS feed(all feeds)

The Editor's Desk
Podcasts
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2014 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Oracle Corporation. in the United States and other countries. Virtua, Inc. is independent of Oracle Corporation. All other trademarks are the sole property of their respective owners.