Push

The a:push component simulates push data from the server. It sends (according to the interval attribute) a very small, (and fast) non-JSF request to the server, in order to check if there are new messages in the queue and if this is true, it performs a standard JSF request.

Example code:

<a4j:push
reRender="myComponent"
interval="3000"
eventProducer="#{messageBean.addListener}" />

In this example, it will check in every 3 seconds (3000 milliseconds) whether there is a message in the queue. If so, the component with id = "myComponent" will be re-rendered.

The eventProducer attribute is needed to point at a method that accepts the PushEventListener instance and registers it, in order to use it inside the bean.

It can be very useful, for example, for asynchronous actions that need periodic page updates.

Let's see a practical use we want to do a complex (and long) job in the background, updating the user about the job status percentage; the Start job button must be disabled after the job calculation starts, and enabled again at the end.

Let's create our backing bean called PushExample inside the book.richfaces.advcm.modules.main.examples.push package and insert this code:

package book.richfaces.advcm.modules.main.examples.push;
@Name("pushExample")
@Scope(ScopeType.CONVERSATION)
public class PushExample implements Runnable {
private Integer completedPercentage = 0;
public Integer getCompletedPercentage() {
return completedPercentage;
}
public void sand setCompletedPercentage(Integer completedPercentage) {
this.completedPercentage = completedPercentage;
}
public void startJob() {
new Thread(this).start();
}
public void run() {
// This is a heavy job
for (int c = 0; c < 10; c++) {
try {
Thread.sleep(1000); // Wait for 1 second
completedPercentage += 10;
// If I finished
if (completedPercentage == 100) {
// Reset
completedPercentage = 0;
}
} catch (InterruptedException e) {
completedPercentage = 0; // Reset on error
}
}
}
}

The component we have created has an Integer property that contains the job status percentage value (from 0 to 100). Also, the component implements the Runnable interface so we can run the job in background (inside a Thread instance) without blocking the frontend during the calculation.

The startJob() method is called by a button (we'll see it soon) and returned immediately after creating a new thread that does the job in the background. As we have made our class Runnable, we need to implement the run() method, that is the one called after the thread creation, for doing the job. The code inside the run() method simulates a job that updates the completedPercentage value every second and resets it when the job is completed.

Now, we have to connect the push component to the backend, in order to be able to communicate with it when new data is ready to be pushed into the frontend.

Let's add the PushEventListener property and a method that will be called by the push component in order to register the listener:

@Name("pushExample")
apush component:PushEventListener property, adding@Scope(ScopeType.CONVERSATION)
public class PushExample implements Runnable {
private PushEventListener listener;
public void addListener(EventListener listener) {
synchronized (listener) {
if (this.listener != listener) {
this.listener = (PushEventListener) listener;
}
}
}
// Other code
}

The addListener method just saves the listener object that can be used to fire a push update, by calling the onEvent method of the listener this way:

listener.onEvent(new EventObject(this));

We can also pass a customized EventObject if we need that.

Coming back to our example, we need to modify the run() method to make it notify the push component at every step (so, every second in our case):

public void run() {
// This is a heavy job
for (int c = 0; c < 10; c++) {
try {
Thread.sleep(1000); // Wait for 1 second
completedPercentage += 10;
// If I finished
if (completedPercentage == 100) {
// Reset
completedPercentage = 0;
}
listener.onEvent(new EventObject(this));
} catch (InterruptedException e) {
completedPercentage = 0; // Reset on error
}
}
}

After every completed part (or in general, when we think there is important data to push), we have just to call the onEvent method, in order to notify the push component that there is new data ready to be pushed.

The /view/examples/push/pushExample.xhtml file is quite simple to understand:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
apush component:/view/examples/push/pushExample.xhtml file <ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:a="http://richfaces.org/a4j"
template="/layout/template.xhtml">
<ui:define name="body">
<h:form>
<a:push interval="1000"
eventProducer="#{pushExample.addListener}" reRender="pushUpdate"/>
</h:form>
<h:form id="pushUpdate">
<h:outputText
value="Job status: #{pushExample.completedPercentage}%"/>
<a:commandButton value="Start job"
action="#{pushExample.startJob}"
disabled="#{pushExample.completedPercentage>0}"
reRender="pushUpdate"/>
</h:form>
</ui:define>
</ui:composition>

You can notice we have connected the push component to the backend using the eventProducer attribute every time there is new data, the push component will re-render the pushUpdate form that shows the completed job percentage and the Start job button. This will be disabled when the first data is pushed and enabled again at the end of the job (when the completedPercentage property is set again to 0).

In order to start the conversation and make the example URL simpler, we are going to add another page (in the same directory of the example) called pushExample.page.xml that contains the configuration we need:

<?xml version="1.0" encoding="UTF-8"?>
<page xmlns="http://jboss.com/products/seam/pages"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd">
<begin-conversation join="true" />
<rewrite pattern="/pushExample" />
</page>

This is what we see when the job has not been started:

Push

And this is what we see when our job is running:

Push
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.237.29