Thursday, March 28, 2013

Richfaces Ajax CDI Push and JBoss



You may not know it, but when you go to a restaurant, you most likely to be served via a method called service à la russe (service in the Russian Style). This is in contradiction to the much older traditional service à la française (service in the French Style).

In the original French Style, all the food was brought from the kitchen into the dining room of the aristocrats or high clergy and served all at once. Then the cooks who lost their jobs during the French revolution, end-up opening places call restaurants to make a living when common people could come to eat and relax (from the verb se restaurer in French), meaning "to restore itself".

French serving style remains in some high class restaurants where small tables or guéridons are moved close to the guest's table where the food preparation is completed and served.



The buffet is a variation of the French Style where the guests help themselves from the table (in French it is traditionally a piece of furniture that looks like a table with drawers called in fact buffet).











On the other hand, the Russian Style that comes from Russia was introduced in the French restaurants during the 19th century where courses are brought to the table sequentially by the waiter. This is now the style in which most modern western restaurants serve food (with some significant modifications).

The place setting (called a cover) for each guest includes a service plate, all the necessary cutlery except those required for dessert, and stemmed glasses for water, wines and champagne

Guests immediately remove their napkins and place them in their laps.

The rule is as such: a filled plate is always replaced with an empty one, and no place goes without a plate until just before the dessert course.

Directly before dessert everything is removed from the place settings but the wine and water glasses. Crumbs are cleared and dessert is served.

As you can see, both styles have very precise rules and mechanisms that must be followed to ensure the best service.




Richfaces itself offers several Ajax server-side push mechanisms to bring data from the server to the client.

Interesting to point-out by the way, that a waiter in french is called "un serveur" (someone who serves) and that the same word is used to design a server in computer science.

These three Ajax Push methods are:
  • 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) 
In a previous article I was explaining how RichFaces Extended Data Tables can be enhanced.

In this article, I will describe how Richfaces Ajax Push CDI can be implemented and deployed specifically on a JBoss container (I am using JBoss application server 7.0)



The Richfaces showcase describes well as usual the java and JSF code needed to implements the CDI Ajax Push.  One thing though, the Push JMS mechanism in not explicated in the show case, but described in the chapter 3 of the documentation.

First what does CDI means?

If you look at your project  facets (I am using Eclipse IDE), you will see that CDI stands for Context and Dependency Injection.

Container/Context Dependency Injection in Java EE 6 decouples the processing threads of  event producers and event consumers by using the Observer pattern in the form of event broadcasting.

An event in CDI is just a regular POJO that can be fired by any class through the use of the Event implementation injected automatically by the container via the @Inject annotation.







 

import java.io.Serializable;

import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Event;

import javax.inject.Inject;
import javax.inject.Named;

import org.richfaces.cdi.push.Push;

@Named
@RequestScoped
public class PushCdiBean implements Serializable {

 private static final long serialVersionUID = 6414191802542861042L;
 public static final String PUSH_CDI_TOPIC = "pushCdi";
 private String message = "";

 @Inject
 @Push(topic = PUSH_CDI_TOPIC)
 Event<string>pushEvent;
 
 
 public void sendMessage() throws Exception {
  if (pushEvent == null) {
  } else {
   pushEvent.fire(message);
  }
  message = "";
 }

 public String getMessage() {
  return message;
 }

 public void setMessage(String message) {
  this.message = message;
 }
}

If you download the source code of the Richfaces showcase (I am using richfaces-4.3.1.Final), you will see that the readme file located under .\richfaces-4.3.1.Final\examples\richfaces-showcase describes useful steps necessary to deploy the sample application on various containers, including JBoss.



First, you need your Maven pom file to have both the Java API CDI and the atmosphere dependencies:
<dependency>
 <groupId>javax.enterprise</groupId>
 <artifactId>cdi-api</artifactId>
 <version>1.1-20130222</version> 
</dependency>
<dependency>
 <groupId>org.atmosphere</groupId>
        <artifactId>atmosphere-runtime</artifactId>
        <version>1.0.10</version>
</dependency>

To be able to inject your CDI bean, your WEB-INF folder needs to contain a bean.xml file:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:weld="http://jboss.org/schema/weld/beans" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://docs.jboss.org/cdi/beans_1_0.xsd http://jboss.org/schema/weld/beans http://jboss.org/schema/weld/beans_1_1.xsd"> </beans>

On your deployment platform, you need JBoss standalone configuration located in .\standalone\configuration\standalone-full.xml to have a JMS topic that match your Push CDI topic:


<jms-destinations>
 <jms-queue name="testQueue">       
  <entry name="queue/test"/>  
  <entry name="java:jboss/exported/jms/queue/test"/>
        </jms-queue>  
 <jms-topic name="pushCdi">
         <entry name="topic/pushCdi"/>  
 </jms-topic>     
</jms-destinations>


You also need to start the JBoss server in full configuration:























Another necessary step is  to create the JMS user account/password:

























From there, you should be able to test your Ajax CDI push application. In my case, the consumer is a popup window that I launch by clicking a button (see code below):

Producer code:

<ui:define name="body">
 <h:form id ="from">
  <a4j:commandButton value="Message Consumer"
   oncomplete="#{rich:component('cdi_message_consumer_popup')}.show();" />
  <h:panelGrid columns="4">
   <h:outputLabel value="Message:" />
   <h:inputText id="messageInput" value="#{pushCdiBean.message}"/>
   <a4j:commandButton value="Send" 
    action="#{pushCdiBean.sendMessage}"
    execute="@form" 
    render="messageInput" 
    oncomplete="#{rich:element('messageInput')}.value=''"/>
  </h:panelGrid>
 </h:form>
 <ui:include src="rf_ajax_push_consumer_popup.xhtml" />
</ui:define>

Consumer code:

<rich:popupPanel 
 id="cdi_message_consumer_popup" 
 modal="false"
 resizeable="false" top="100" 
 left="300" 
 autosized="true"
 domElementAttachment="parent">
 <f:facet name="header">
  <h:outputText value="Ajax Push/CDI Message Consumer    " />
 </f:facet>
 <f:facet name="controls">
  <h:outputLink value="#"
   onclick="#{rich:component('cdi_message_consumer_popup')}.hide(); return false;">
   <h:outputText value="X" styleClass="textHeader" />
  </h:outputLink>
 </f:facet>
 <h:form>
  <h:panelGrid columns="3">
   <a4j:push address="pushCdi" 
    onerror="alert('error: ' + event.rf.data)"
    ondataavailable="jQuery('<li />').prependTo('#messages').text(event.rf.data)">
   </a4j:push>
   <ul id="messages" />
  </h:panelGrid>
 </h:form>
</rich:popupPanel>















The message (simple string) is send to the server and pushed back to the browser. The original message is then cleaned:
















A big thank to my colleague Asha Ambikavijayakumaran for figuring out all the tricky details for the JBoss deployment for this Richfaces showcase!


All ingredients and open source code related to this recipe can be found at YummyCode on the JSF Plate project.