JSFweb design

Primefaces RemoteCommand: Lazy Loading Revisited


Last year I published an article on lazy loading in JSF pages. This article became one of this blog’s most popular articles. Obviously I’m not the only developer suffering from slow back ends.

Most likely you already know what lazy loading is about: it’s about slow back ends. If you have to deal with a slow back end you shouldn’t call it when initializing your bean. Your JSF page is shown after your bean has been initialized completely and after every bean property displayed by the page has been read.

So you’d rather have a bean that’s constructed and initialized quickly, and your getters shouldn’t waste time. But what if it takes – say – 30 seconds to initialize the bean?

Sometimes it’s a good solution to show an incomplete version of your page immediately, leaving a couple of fields blank. The idea is to fill the blank fields a couple of seconds later, when your back end has finished collecting data.

Last year I1 proposed to use <prime:poll> to do so. The poll component allows you to call a back end method every couple of seconds, and to update the screen afterwards. The idea was to activate poll as fast as possible (one second), and to stop it after the first call. The solution works, and it helped my team a lot to make the user interface more responsive.

But – well, the solution I proposed last year doesn’t exactly speed up the program. Quite the contrary, it adds an extra second until the back end data is displayed. I didn’t like the extra second, and I didn’t like the generated javascript code. <prime:poll> dedicates a timer2 to the task. Javascript only provides a single timer, so timers aren’t a resource to be wasted.

To solve the problem, <prime:remoteCommand> comes in handy. Originally <prime:remoteCommand> is intended to call back end bean methods from Javascript. Combine it with the update property to update the screen. Another property, autoRun, allows you to use <prime:remoteCommand> without Javascript code. autoRun="true" makes sure the back end method is called automatically after the form is displayed. Insert the remoteCommand immediately before the closing </form> tag:

    <prime:remoteCommand autoRun="true" action="#{myBean.init}"
                         update="content" name="longRunningInit"/>
</form>

Be careful to define the update property correctly. The updated region of the screen shouldn’t include the remoteCommand. You don’t want to get an infinite loop.

You can call an arbitrary method of the bean. If you call <prime:remoteCommand> from Javascript, you can even pass parameters to the bean’s method. Of course, using autoRun="true" doesn’t allow us to pass parameters, so a simple parameterless method will do.

For the sake of completeness, I’ll terminate showing you both the sample bean and the sample JSF page:

package de.beyondjava.jsf.sample;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.ActionEvent;
import javax.validation.constraints.Max;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

@ManagedBean
@ViewScoped
public class AdditionBean implements Serializable {

   private String number1 = "1";

   private String number2 = "2";
   private int result = 0;

   public String getNumber1() {
      return number1;
   }

   public void setNumber1(String number1) {
      this.number1 = number1;
   }

   public String getNumber2() {
      return number2;
   }

   public void setNumber2(String number2) {
      this.number2 = number2;
   }

   public int getResult() {
      return result;
   }

   public void setResult(int result) {
      this.result = result;
   }

   public void add() {
      result = Integer.valueOf(number1) + Integer.valueOf(number2);
   }

   public void minus(ActionEvent evt) {
      result = Integer.valueOf(number1) + Integer.valueOf(number2);
   }

   public void init() {
      try {
         Thread.currentThread().sleep(3000);
      }
      catch (InterruptedException e) {
      }
      System.out.println("Init!");
      number1 = "55";
   }
}
<f:view xmlns="http://www.w3c.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/ui"
	xmlns:prime="http://primefaces.org/ui" locale="en-us">
	<h:head>
		<link type="text/css" rel="stylesheet" href="themes/bluesky/skin.css" />
	</h:head>
	<h:body>
		<h:form>
			<h:panelGrid columns="3" id="content">
				<h:outputLabel value="First number" />
				<h:inputText label="First number"
				    value="#{additionBean.number1}"
					id="firstNumber" />
				<h:message for="firstNumber" />
				<h:outputLabel value="First number" />
				<h:inputText label="Second number" 
				    value="#{additionBean.number2}"
					id="secondNumber" />
				<h:message for="secondNumber" />
				<h:commandButton type="submit" 
				    value="add"
					action="#{additionBean.add}" 
					update="content" />
				<h:outputLabel value="" />
				<h:commandButton value="subtract"
					actionListener="#{additionBean.minus}" 
					update="content" />
				<h:outputLabel value="Result"/>
				<h:inputText label="Result" 
				    value="#{additionBean.result}"
					id="result" />
				<h:message for="secondNumber"/>

			</h:panelGrid>
			<prime:remoteCommand autoRun="true" 
			    action="#{additionBean.init}"
				name="longRunningInit" 
				update="content" />
		</h:form>
		<h:messages />
	</h:body>
</f:view>
  1. To be precisely, it was my collegue RĂ¼diger Kowalski who worked out the idea. I only published it on this blog.
  2. To be precisely, it calls window.setInterval().