Showing posts with label jsf. Show all posts
Showing posts with label jsf. Show all posts

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.





Saturday, February 9, 2013

Advanced RichFaces Extended Data Tables

 
With Mardi Gras and Carnival around the corner, this is crêpe season!

This post is the first of a set of recipes that describe useful tips and reusable code and patterns related to Java, JSF 2.0 and RichFaces 4.0.  In this article I am describing practical integration code when using advanced Richfaces Extended Data Tables.

The RichFaces showcase describes well how to start creating your own extendedDataTable. However, here are some additional personal ingredients that can be very handy when preparing an appealing stack of JSF based web pages.





1) Setting your Table

The first time your try to put together a RichFaces extendedDataTable, you might encounter the following behavior: your table does not look like as you expected it: columns have a default size (the length of the label) and the whole size is the size of your whole window, so you end up with a large white space where they are no columns:


 One reason could be that no column or table size has been specified:


 <rich:extendedDataTable id="table" value="#{countries.countryItems} var="country" >
    <f:facet name="header">
        <h:outputText value="Countries" />
    </f:facet>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Name" />
        </f:facet>
        <h:outputText value="#{country.name}" />
    </rich:column>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Capital" />
        </f:facet>
        <h:outputText value="#{country.capital}" />
    </rich:column>
    <rich:column>
        <f:facet name="header">
            <h:outputText value="Language(s)" />
        </f:facet>
        <h:outputText value="#{country.languages}" />
    </rich:column>
</rich:extendedDataTable>


One way to quickly fix this is to assign specific sizes to your columns and headers (in my case these are absolute values in pixels and have adjusted the values to take into account the height of a row and the presence of a vertical scroller).  I have also added single selection mode so I can click on a row to retrieve more information about a certain item:

<rich:extendedDataTable id="table" value="#{countries.countryItems}"
    var="country" selection="#{countries.selection}" 
    style="height:190px; width:503px;"
    selectionMode="single">
    <a4j:ajax execute="@form" event="selectionchange" listener="#{countries.selectionListener}"/>
        <f:facet name="header">
            <h:outputText value="Countries" />
        </f:facet>
        <rich:column width="100px">
            <f:facet name="header">
                <h:outputText value="Name" />
            </f:facet>
            <h:outputText value="#{country.name}" />
        </rich:column>
        <rich:column width="100px">
            <f:facet name="header">
                 <h:outputText value="Capital" />
            </f:facet>
            <h:outputText value="#{country.capital}" />
        </rich:column>
        <rich:column width="300px">
            <f:facet name="header">
                <h:outputText value="Language(s)" />
            </f:facet>
            <h:outputText value="#{country.languages}" />
        </rich:column>
</rich:extendedDataTable>
















2) Interaction improvements

Let say now that you want to add a button to load or refresh the information in the table and that this takes some time because you are connected to a remote service. You may want to show to the end-user an indicator that some processing or data retrieval is happening (for this example, I added a waiting function in the iem list bean to simulate a few seconds wait).

I propose to use an animated GIF and take advantage of the RichFaces a4j:status (an indicator of an Ajax request. It has two states: start and stop. The start state indicates that an Ajax request is in progress. When an Ajax response is returned, the component switches to the stop state).

In this case, I refer to a4j:status every time I click on the refresh button to download the countries statistics. I have also added an animated GIF file called processing.gif in my webapp/img folder and top aligned both the button and the ajax indicator into a JSF panel grid:


<h:panelGroup>
    <h:panelGrid columns="2" columnClasses="alignTop, alignTop">
        <a4j:commandButton value="Refresh" status="refreshTable"
     oncomplete="#{countries.refresh()}" />
        <a4j:status name="someProcessing">
            <f:facet name="start">
         <h:graphicImage value="/img/processing.gif" />
     </f:facet>
        </a4j:status>
    </h:panelGrid>
</h:panelGroup>

As a result, the processing indicator appears next to the button when it is clicked and disappear after the table has been refreshed.


















In fact, you can use the same indicator when selecting a row to display detailed information about an item if the retrieval of the additional information takes too long for the user (e.g. more than a couple of seconds):


<a4j:ajax execute="@form" event="selectionchange" status="someProcessing" listener="#{countries.selectionListener}" />


3) Adding some coloring and flavor

If you don't have a predefine look and feel (e.g. a reusable template or UI toolkit), you can easily use the themes and skins that come with RichFaces.  A skin can be quickly added to the web.xml file as follow:


<context-param>
    <param-name>org.richfaces.skin</param-name>
    <param-value>wine</param-value>
</context-param>

Some of my favorites predefined skins are deepMarine and wine:

 
















4) The missing ingredients

Even though the RichFaces Extended Data Tables have a lot of features such as filtering, sorting, scrolling, frozen columns, here are always missing ingredients that you would like to use to offer a better experience to the end user. One that you will not find in the ExtendedDataTable is the wrapping of text in a column or a robust column horizontal scrolling. Hopefully this feature will be added in future release.


5) Always give a tip if you can

Offering tips is generally a good practice. It makes feel everybody happy: the person who provides it knowing that he/she has done a good job, and the end-user who enjoys it and saves time using them.

In this example, I have added a column to to indicate which countries have a GDP above one Trillion US Dollars. When the use hovers the mouse above the checkbox or the name of the country, a tooltip appears and shows the GDP number for the selected country.

















Tooltips can be easily added as follow:

<rich:column styleClass="#{msg.status}" width="35px">
    <f:facet name="header">
        <h:outputText value="GDP > $1T" />
    </f:facet>
    <rich:tooltip mode="client" target="largeGDPCountry">
        <h:outputText value="#{country.name} - 2011 GDP: #{country.gdp} > $1T" />
    </rich:tooltip>
    <h:graphicImage id="largeGDPCountry" value="/img/checkmark.png" rendered="#{country.largeGdp}" alt="GDP" />
</rich:column>
<rich:column width="100px">
    <f:facet name="header">
        <h:outputText value="Name" />
    </f:facet>
    <h:outputText id="countryName" value="#{country.name}" />
    <rich:tooltip mode="client" target="countryName">
        <h:outputText value="#{country.name} - 2011 GDP: #{country.gdp} $M" />
    </rich:tooltip>
</rich:column>


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