5.8. <a4j:push>

The <a4j:push> component performs real-time updates on the client side from events triggered at the server side. The events are pushed out to the client through the RichFaces messaging queue. When the <a4j:push> component is triggered by a server event, it can in turn cause Ajax updates and changes.
The <a4j:push> component uses the Comet model for pushing data to the client.

5.8.1. Setting up Push

Using the Push component requires configuration steps which depends on an environment in which the Push is used:

5.8.1.1. Installing runtime dependencies

The <a4j:push> uses an Atmosphere framework for transporting messages. In order to use the Atmosphere on the server-side, it is necessary to add Atmosphere libraries into a project.
In a Maven-based project, you should add atmosphere-runtime as a runtime dependency (its version is managed by richfaces-bom that your project should be importing, check "RichFaces Developer Guide" for details of starting with Maven-based project):
<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-runtime</artifactId>
</dependency>
For non-Maven-based projects, it is necessary to add dependencies manually - see the Project libraries and dependencies section of RichFaces Developer Guide for more details.

5.8.1.2. Registering Push servlet

The Push requires a PushServlet registered in web application and listening for Push client connections.
In the Servlets 3.0 and higher environments, the servlet will be registered automatically.
However in the Servlets 2.5 and lower environments, the servlet needs to be registered manually in web.xml:
<!-- Push Servlet - listens for user sessions -->
<servlet>
    <servlet-name>Push Servlet</servlet-name>
    <servlet-class>org.richfaces.webapp.PushServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Push Servlet</servlet-name>
    <url-pattern>/__richfaces_push</url-pattern>
</servlet-mapping>

<!-- setups servlet-mapping in RichFaces configuration -->
<context-param>
    <param-name>org.richfaces.push.handlerMapping</param-name>
    <param-value>/__richfaces_push</param-value>
</context-param>

Note

When you attempt to register the Push servlet manually in Servlet 3.0 environments, RichFaces will detect that the Push servlet is already registered and avoid initializing it again.
However, be sure to setup the Push servlet to support asynchronous requests - modify the servlet registration from the previous web.xml snippet as follows:
<servlet>
    <servlet-name>Push Servlet</servlet-name>
    <servlet-class>org.richfaces.webapp.PushServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
</servlet>

Note

Although a container you use supports Servlets 3.0, you may experience problems with using asynchronous servlets.
It is possible to force the Atmosphere to use a blocking I/O approach with the following web.xml configuration:
<context-param>
    <param-name>org.atmosphere.useBlocking</param-name>
    <param-value>true</param-value>
</context-param>

5.8.2. Server-side Push methods

The Push events can be fired on the server-side in several ways:
  • TopicsContext - accesses a RichFaces message queue directly
  • Push CDI - uses the CDI Event mechanism to fire messages
  • Push JMS - the RichFaces Push consumes messages from an enterprise messaging system and exposes them to the client (tightly coupled with the JMS runtime)

5.8.3. Client-side Push methods

On the client side, push notifications may be processed in the following ways:
  • ondataavailable event handler (serialized message is available)
  • Client behaviors attached to dataavailable event

5.8.4. Push Topics

The Push messages are delivered to the client based on a TopicKey's name (e.g. someTopic).
The TopicKey can optionally include a subtopic name (e.g. subtopic@anotherTopic).
On the client side, the topic is represted by an <a4j:push>'s attribute address.

Note

The format for the name of the push topic is very close to the JMS topic name and thus enables a seamless transport of JMS messages to the RichFaces message queue.

Note

Since the topic key can contain EL expressions, it is possible to achieve dynamic end-points (e.g. addressing specific clients).
You need to push a message by using TopicContext.publish(TopicKey key, Object message) or using CDI events to publish message to dynamically evaluated topic key.
The <a4j:push>'s attribute address accepts EL expressions.

5.8.5. Handling a push message

A push message sent from the server to the <a4j:push> component on the client will cause it to trigger any event handlers defined using the dataavailable event handler.
The <a4j:push> component should also include the onerror event handler to inform the user when an error has occurred with the push messages.
<a4j:push> can be used for either immediate processing of messages (like in the previous example) or it can trigger a partial page update. Check out following samples:

Example 5.5. Handling a push message

<a4j:push address="chat"
          onerror="alert(event.rf.data)"
          ondataavailable="chat.addMessage(event.rf.data)" />
This example uses the dataavailable event attribute with some JavaScript to update messages in a chat room. The event.rf.data parameter contains Push message data serialized to JavaScript.

Example 5.6. Updating DOM for each push message

<a4j:push address="chat"
          onerror="alert(event.rf.data)">
    <a4j:ajax event="datavailable" render="chat" />
</a4j:push>
This example uses the dataavailable event handler to trigger an AJAX request and a partial page update.

5.8.6. Handling a push subscription

The <a4j:push> component establishes connection with server on complete page load (when document is ready).
It means that the application starts to handle push messages once the page is completely loaded.
However time-critical applications may require keeping client stricly synchronized with the server state.
For such applications you may use onsubscribed event handler, which is triggered every time the given component is successfully subscribed to the address/topic it listens to (on a page load and on each AJAX re-render).

Example 5.7. The time-critical updates in stock application

<a4j:push address="stockUpdates"
          onerror="alert(event.rf.data)">
    <a4j:ajax event="dataavailable" render="stocksTable" />
	<a4j:ajax event="subscribed" render="stocksTable" />
</a4j:push>
This example uses the subscribed event to update the table content once the push component is subscribed to the topic, ensuring that the table content is not stale.

5.8.7. Using TopicsContext to publish message

Messages could be produced using the TopicsContext interface directly as in the following sample:
private TopicKey topicKey = new TopicKey("chat");

public void initializeTopic() {
	TopicsContext topicsContext = TopicsContext.lookup();
	topicsContext.getOrCreateTopic(topicKey);
}

public void sendMessage(String message) throws MessageException {
    TopicsContext topicsContext = TopicsContext.lookup();
    topicsContext.publish(topicKey, message);
}
A topic needs to first be created using TopicsContext#getOrCreate(TopicKey) where TopicKey is the name of the topic. A message to the topic can be sent using the method: TopicsContext#publish(topicKey, message).

5.8.8. Integrating Push with CDI events

An alternative way of producing messages is to use the CDI event mechanism.
Push notifications can be produced by annotating a CDI event injection point with the @Push annotation, which specifies an end-point (topic name).
The payload of the message is the serialized object sent using the CDI event interface (Event.fire(T object)).
@Inject
@Push(topic = "chat")
Event<String> pushEvent;

public void sendMessage(String message) {
    pushEvent.fire(message);
}

5.8.9. Push and JMS integration

An integration of the RichFaces Push and the Java Messaging Service (JMS) allows to write robust interactive applications.

5.8.9.1. Enabling JMS integraction

The JMS integration needs to be enabled in web.xml with a following configuration:
<context-param>
    <param-name>org.richfaces.push.jms.enabled</param-name>
    <param-value>true</param-value>
</context-param>

5.8.9.2. Configuring JMS backend

The JMS instance on the back-end must be configured to work with your <a4j:push> components.

Note

Refer to the Red Hat JBoss Enterprise Application Platform Administration and Configuration Guide for details on managing JBoss Enterprise Application Platform through the Administration Console.

Example 5.8. JMS server configuration

This simple example describes the JMS server configuration required for a pushing server date to the client.
The JMS server needs to be setup in order to propagate JMS messages to Push components. Create a new JMS topic using the following settings:
  • Name: datePush
  • JNDI name: /topic/datePush
  • Use the default settings for other options.
Add a single role for the topic in the same form using the following settings:
  • Name: guest
  • Send: true
  • Consume: true
  • Create subscriber: true
  • Delete subscriber: true
  • Create durable subscriber: true
  • Delete durable subscriber: true
Ensure the Create durable subscriber and the Delete durable subscriber options are set to true for proper push functionality.

Note

Durable subscriptions receive all events, including those events which were sent while the push component was not connected.
Refer to JMS Documentation for details on configuring the JMS Server.

Note

RichFaces looks for the JMS Connection Factory on the JNDI context /ConnectionFactory by default.
The prefix /topic is used for deriving JMS topic names from Push topic names.
When integrating component into an enterprise system, this defaults can be changed.
Use following web.xml parameters to change default values: org.richfaces.push.jms.connectionFactory, org.richfaces.push.jms.topicsNamespace.
When RichFaces obtains a connection, an empty user name is used with an empty password.
Use following web.xml parameters or equivalent JVM parameters to change default values: org.richfaces.push.jms.connectionUsername, org.richfaces.push.jms.connectionPassword.

5.8.9.3. Sending and receiving Push messages using JMS

The JMS message which should be propagated to Push needs to be created with the method session.createObjectMessage(message);.
The message could be then published using publisher.publish(message); like in a following example:

Example 5.9. Sending messages using JMS

TopicConnection connection;
TopicSession session;
TopicPublisher publisher;

public void sendCurrentDate() throws JMSException {
    String currentDate = new Date().toString();
    ObjectMessage message = session.createObjectMessage(message);
    publisher.publish(message);
}

// messaging needs to be initialized before using method #sendCurrentDate()
private void initializeMessaging() throws JMSException, NamingException {
    if (connection == null) {
        TopicConnectionFactory tcf = (TopicConnectionFactory) InitialContext.doLookup("java:/ConnectionFactory");
        connection = tcf.createTopicConnection();
    }
    if (session == null) {
        session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    }
    if (topic == null) {
        topic = InitialContext.doLookup("topic/datePush");
    }
    if (publisher == null) {
        publisher = session.createPublisher(topic);
    }
}
Receiving messages from a JMS queue doesn't differ from receiving messages sent by the TopicsContext or using CDI events.

Example 5.10. Receiving messages using JMS

<a4j:push id="datePush" address="datePush"
            ondataavailable="jQuery(#{rich:element('serverDate')}).text(event.rf.data)" />
            
<a4j:outputPanel id="serverDate" layout="block">
    <i>waiting for event...</i>
</a4j:outputPanel>
The above example demonstrates a simple use of the <a4j:push> tag that causes an immediate update of the page content.

5.8.10. Reference data

  • component-type: org.richfaces.Push
  • component-class: org.richfaces.component.UIPush
  • component-family: org.richfaces.Push
  • renderer-type: org.richfaces.PushRenderer