JBoss.orgCommunity Documentation
This chapter details the basic components that respond to a user action and submit an Ajax request.
The <a4j:ajax>
behavior allows Ajax capability to be added to a non-Ajax component. The non-Ajax component must implement the ClientBehaviorHolder
interface for all the event attributes that support behavior rendering.
The <a4j:ajax>
behavior is placed as a direct child to the component that requires Ajax support.
Point the event
attribute to the standard JSF event that triggers the behavior. If the event
attribute is not defined, the behavior is triggered on the event that normally provides interaction behavior for the parent component.
Example 3.1. <a4j:ajax>
example
<h:panelGrid columns="2">
<h:inputText id="myinput" value="#{userBean.name}">
<a4j:ajax event="keyup" render="outtext" />
</h:inputText>
<h:outputText id="outtext" value="#{userBean.name}" />
</h:panelGrid>
client-behavior-renderer-type
: org.ajax4jsf.behavior.Ajax
behavior-id
: org.ajax4jsf.behavior.Ajax
handler-class
: org.richfaces.view.facelets.html.AjaxHandler
behavior-class
: org.ajax4jsf.component.behavior.AjaxBehavior
client-behavior-renderer-class
: org.ajax4jsf.renderkit.AjaxBehaviorRenderer
The <a4j:param>
behavior combines the functionality of the JavaServer Faces ( JSF) components <f:param>
and <f:actionListener>
.
Basic usage of the <a4j:param>
requires three main attributes:
value
attribute is the initial value of the parameter.
assignTo
attribute defines the bean property. The property is updated if the parent command component performs an action event during the Process Request phase.
Example 3.2, “<a4j:param> example” shows a simple implementation along with the accompanying managed bean.
Example 3.2. <a4j:param>
example
<h:form id="form">
<a4j:commandButton value="Set name to Alex" reRender="rep">
<a4j:param name="username" value="Alex" assignTo="#{paramBean.name}"/>
</a4j:commandButton>
<h:outputText id="rep" value="Name: #{paramBean.name}"/>
</h:form>
public class ParamBean {
private String name = "John";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
When the name
parameter of the bean to Alex
, and displays the name in the output field.
The <a4j:param>
tag can be used with non-Ajax components in addition to Ajax components. This includes components which are working through the GET
request, such as the <h:link>
and <h:button>
components. In this way, data model values can also be updated without any Java code on the server side.
The converter
attribute can be used to specify how to convert the value before it is submitted to the data model. The property is assigned the new value during the Update Model phase.
If the validation of the form fails, the Update Model phase will be skipped and the property will not be updated.
Variables from JavaScript functions can be used for the value
attribute. In such an implementation, the noEscape
attribute should be set to true
. Using noEscape="true"
, the value
attribute can contain any JavaScript expression or JavaScript function invocation, and the result will be sent to the server as the value
attribute.
Example 3.3. Passing client-side parameters
<h:form>
<a4j:commandButton value="Show Screen Size" render="infoPanel">
<a4j:param name="w" value="screen.width"
assignTo="#{paramBean.screenWidth}" noEscape="true" />
<a4j:param name="h" value="screen.height"
assignTo="#{paramBean.screenHeight}" noEscape="true" />
</a4j:commandButton>
<h:panelGrid columns="2" id="infoPanel">
<h:outputText value="Width:" />
<h:outputText value="#{paramBean.screenWidth}" />
<h:outputText value="Height:" />
<h:outputText value="#{paramBean.screenHeight}" />
</h:panelGrid>
</h:form>
The command button triggers the <a4j:param>
behaviors and renders the output text. The <a4j:param>
behaviors pass client-side parameters for the screen width and height through the backing bean. These parameters are then used to populate the output text values.
Use the <a4j:actionListener>
tag to register an ActionListener
class on a parent action component. The class provided as a listener must implement the javax.faces.event.ActionListener
interface. Multiple listener methods can be registered on an action component in this way.
The <a4j:actionListener>
tag differs from the standard JSF tag by allowing a listener method to be defined instead of just a class. Use the listener
attribute to define the listener method.
The <a4j:commandButton>
component is similar to the JavaServer Faces ( JSF) <h:commandButton>
component, but additionally includes Ajax support.
Button controls are typically used to perform complete form submissions for data storing. As a consequence, the <a4j:commandButton>
component has the execute="@form"
setting by default. To limit rendering to a different scope, redefine the execute
attribute.
The <a4j:commandButton>
requires only the value
attribute to function. Use the value
attribute to specify the text of the button.
By default, the <a4j:commandButton>
uses the click
event instead of the submit
event.
The <a4j:commandLink>
component is similar to the JavaServer Faces ( JSF) <h:commandLink>
component, except that it includes plugged-in Ajax behavior.
Link controls are typically used to perform complete form submissions for data storing. As a consequence, the <a4j:commandLink>
component has the execute="@form"
setting by default. To limit rendering to a different scope, redefine the execute
attribute.
The <a4j:commandLink>
requires only the value
attribute to function. Use the value
attribute to specify the text of the link.
The <a4j:commandLink>
uses the click
event instead of the submit
event.
The <a4j:jsFunction>
component performs Ajax requests directly from JavaScript code and retrieves server-side data. The server-side data is returned in JavaScript Object Notation ( JSON) format prior to the execution of any JavaScript code defined using the oncomplete
attribute.
The <a4j:jsFunction>
component requires the data
attribute. Use the data
attribute to define where the retrieved server-side data is stored.
Example 3.4, “<a4j:jsFunction> example” shows how an Ajax request can be initiated from the JavaScript and a partial page update performed. The JavaScript function can be invoked with the data returned by the Ajax response.
Example 3.4. <a4j:jsFunction>
example
<table width="400">
<tbody>
<tr>
<td>
<span onmouseover="updateName('Kate')"
onmouseout="updateName('')">Kate</span>
</td>
<td>
<span onmouseover="updateName('John')"
onmouseout="updateName('')">John</span>
</td>
<td>
<span onmouseover="updateName('Alex')"
onmouseout="updateName('')">Alex</span>
</td>
</tr>
<tr>
<td colspan="3">
Name: <b><h:outputText id="showname" value="#{functionBean.text}" /></b>
</td>
</tr>
</tbody>
</table>
<h:form>
<a4j:jsFunction name="updateName" render="showname">
<a4j:param name="name" assignTo="#{functionBean.text}"/>
</a4j:jsFunction>
</h:form>
The output text for the name is changed depending on which table cell the user hovers over with the mouse. The <a4j:jsFunction>
component manages the updating and display of the name.
The <a4j:jsFunction>
component allows the use of the <a4j:param>
component or the JavaServer Faces <f:param>
component to pass any number of parameters for the JavaScript function.
The <a4j:poll>
component allows periodical sending of Ajax requests to the server. It is used for repeatedly updating a page at specific time intervals.
The interval
attribute specifies the time in milliseconds between requests. The default for this value is 1000 ms (1 second).
The <a4j:poll>
component can be enabled and disabled using the enabled
attribute. Using Expression Language ( EL), the enabled
attribute can point to a bean property to apply a particular attribute value.
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.
Using the Push component requires configuration steps which depends on an environment in which the Push is used:
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 richfaces-push-depchain
as a runtime dependency:
<dependency>
<groupId>org.richfaces</groupId>
<artifactId>richfaces-push-depchain</artifactId>
<type>pom</type>
<version>4.5.5.Final</version>
<scope>runtime</scope>
</dependency>
By declarating a dependency chain, all the required runtime dependencies such as atmosphere-runtime
will be added transitively to your project.
For non-Maven-based projects, it is necessary to add dependencies manually - check "RichFaces Developer Guide", section "Project libraries and dependencies" for details.
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>
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>
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>
The Push events can be fired on the server-side in several ways:
On the client side, push notifications may be processed in the following ways:
ondataavailable
event handler (serialized message is available)
dataavailable
event
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
.
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.
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.
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 3.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 3.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.
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 3.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.
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)
.
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);
}
An integration of the RichFaces Push and the Java Messaging Service ( JMS) allows to write robust interactive applications.
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>
The JMS instance on the back-end must be configured to work with your <a4j:push>
components.
Refer to the JBoss EAP Administration and Configuration Guide for details on configuring JMS in JBoss EAP.
Example 3.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.
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.
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
.
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 3.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 3.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.