Jim Driscoll's Blog

Notes on Technology and the Web

Request aggregation in JSF 2 Ajax

leave a comment »

I’ve had a few requests for request aggregation, ala RichFaces queues, in JSF 2. This was deliberately not included in JSF 2.0, but it will be considered for JSF 2.1. The reason why is simple – there was simply not very much time, once all the base Ajax work was completed, to add any additional features. However, adding this functionality yourself isn’t actually very hard. Here’s an example of how.

For those not familiar with the idea of request aggregation, the idea is a pretty simple one: in cases where the user may generate a large number of requests (for instance, with the keyup event), you’re going to want to wait and see if you can bundle the requests together, so you don’t spam the server with thousands of tiny little requests.

The example will have two parts: a JSF page, and some backing JavaScript. The end result will be a program which accepts input, and echos it out to another part of the page via an Ajax request to the server. There’s also a status area to show a little of what’s going on during the call.

Here’s the form:

   1 <h:form id="form1" prependId="false">
   2     <h:outputScript name="jsf.js" library="javax.faces" target="head"/>
   3     <h:outputScript name="javascript/aggregate.js" target="head"/>
   5     Output: <h:outputText id="out1" value="#{echo.str}"/>
   6     <br/>
   7     Input: <h:inputText id="in2" value="#{echo.str}" autocomplete="off"
   8                         onkeyup="aggregate('out1 in1', this)"/>
   9     <br/>
  10     Status:
  11     <br/>
  12     <textarea id="status" rows="10" cols="50" readonly="readonly"/>
  13 </h:form>

And here’s the backing JavaScript:

   1 var increment = 1000; 
   2 var token;
   3 function aggregate(target, element) {
   4     window.clearTimeout(token);
   5     addStatusMessage("cleared request, requeued");
   6     var send = function send() {
   7         jsf.ajax.request(element, null, {render: target});
   8     };
   9     token = window.setTimeout(send, increment);
  10 }
  12 function addStatusMessage(message) {
  13     var statusElement = document.getElementById("status");
  14     var status = statusElement.value;
  15     var now = new Date();
  16     var timestamp = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
  17     status = timestamp + ' ' + message + '\n' + status;
  18     statusElement.value = status;
  19 }
  21 jsf.ajax.addOnEvent(function(data) {
  22     if (data.status === "begin") {
  23         addStatusMessage("request sent");
  24     }
  25 });

This program is simple enough that it’s function should be pretty self evident – but in case you’ve never worked with JavaScript timers, here’s the control flow.

When you type a character into the input field, the aggregate function is called (JSF page line 8). If an outstanding request is already there, it will be canceled (JavaScript line 4), and a status message will be written (JavaScript lines 12-19) to a readonly textarea in the page (JSF page line 12). Then, a new request will be submitted, which will go off after 1 second (JavaScript line 9). If you type a new character before the second has elapsed, then the first request is canceled (JS line 4), before being submitted again with a new value (JS line 9). If a whole second goes by without a new keypress, then the request will finally be sent to the server, which will also trigger calling the event function (JS lines 21 – 24), which in turn writes out a status (JS lines 12-19), to the textarea (JSF line 12).

So, all told, the aggregation code was about 6 lines of JavaScript. And while that may be a trifle annoying, I can only assume that anyone writing a component like Autocomplete will include this into the component so you never need see it.

As always, feel free to ask questions on this post in the comments.

(This article originally published on my java.net blog on October 19, 2009.)


Written by jamesgdriscoll

February 9, 2010 at 11:18 PM

Posted in ajax, JSF

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: