TOC PREV NEXT INDEX



PDF
ICEfaces Online Reference




 


 




Tutorial: Clustered Chat


ICEfaces EE provides a small sample application called Clustered Chat that shows how to convert a regular ICEfaces application into one that can broadcast render requests across nodes in a cluster. The purpose of the application is to illustrate key points of server-initiated rendering in a cluster, and so has purposefully been kept as simple as possible. It is not intended as an example of best practices for GUI design, database access, etc. Both examples can be built in the same way as the rest of the tutorials using Ant. Refer to Ant in the ICEfaces Getting Started Guide. This example is JBoss-specific, but the basic approach is applicable to other application servers.

The best way to run the examples is to create a small JBoss cluster. A full description of how to do this is beyond the scope of this document but with JBoss, it is fairly easy to create a cluster. The latest versions of JBoss come with three different configurations: minimal, default, and all. The all configuration is perfectly suited to running clustered ICEfaces applications. By default, any JBoss servers started with the all configuration will automatically find each other and create a default cluster. So if you have two machines, simply start JBoss on each one using the provided run.sh/run.bat script.

> ./run.sh -c all
 

If other developers are running JBoss servers with the all configuration, you may want to provide a unique name for your cluster to avoid confusion:

> ./run.sh -c all -g ICEfacesDevCluster
 

The Clustered Chat example application comes in two parts.

Building and deploying clusteredChat1

The first version of the application can be found in the following location:

<icefaces-install-dir>/tutorial/clusteredChat1
 

This version of Clustered Chat is an ICEfaces chat application using the basic RenderManager available in ICEfaces CE. For simplicity, the example uses an in-memory database. Before you build the application, you must configure it so that one of the nodes in the cluster is selected as the database host. This can be done in the faces-config.xml file which can be found in:

<icefaces-install-dir>/tutorial/clusteredChat1/web/WEB-INF
 

You should change the managed property of the chatRoom bean from "localhost" to the IP address of one of the nodes in the cluster.

	...
 
    <managed-property>
 
        <property-name>dbHost</property-name>
 
        <value>localhost</value>
 
    </managed-property>
 
  ...
 

Once you have made this change, you can build and deploy this application to your cluster. To deploy the application to the cluster, simply copy or drop the clusteredChat1.war file into the
<jboss-install-dir>/server/all/farm directory. JBoss takes care of pushing the archive to the other nodes in the cluster.

After the application has been successfully deployed, point your browser at the node you specified to host the database to login to chat (for example, http://[node1]:8080/clusteredChat1). This initializes the database.

Everyone is in the same chatroom. The user list and message transcript are stored in the shared database. Now point another browser (or browser instance or browser tab) at a different node in the cluster (for example, http://[node2]:8080/clusteredChat1). The behavior you should notice is that you can chat on either node but that messages sent on one node are not seen by the client on the other node unless the client does something to update the page (like send a chat message). You can send many messages from one node but the other node will not be updated until it sends a message. At that point it catches up by pulling all the latest information out of the database.

Building and deploying clusteredChat2

The second version of the application can be found in the following location:

<icefaces-install-dir>/tutorial/clusteredChat2
 

This version has been modified to use the BroadcastRenderManager so that render requests can be relayed across all the nodes in the cluster. Here are the steps necessary to accomplish this.

1. Change from RenderManager to BroadcastRenderManager
In the first version of the application, we relied on the basic RenderManager. To support rendering in the cluster, we need to upgrade to the BroadcastRenderManager. This is done in:
<ICEfaces-install-dir>/tutorial/clusteredChat2/web/WEB-INF/faces-config.xml 
 

 
    <managed-bean>
 
        <managed-bean-name>renderMgr</managed-bean-name>
 
        <managed-bean-class>
 
            com.icesoft.faces.async.render.RenderManager
 
        </managed-bean-class>
 
        <managed-bean-scope>application</managed-bean-scope>
 
    </managed-bean>
 

becomes:

    <managed-bean>
 
        <managed-bean-name>renderMgr</managed-bean-name>
 
        <managed-bean-class>
 
            com.icesoft.faces.async.render.broadcast.BroadcastRenderManager
 
        </managed-bean-class>
 
        <managed-bean-scope>application</managed-bean-scope>
 
    </managed-bean>
 
2. Change JMS configuration.
JBoss-specific JMS configuration is described early in this chapter. Specifically, the changes required are:
See JBoss 4.0 in this guide for details.
3. Add the icefaces-enterprise.jar.
The BroadcastRenderManager is part of ICEfaces EE so we need to include the icefaces-enterprise.jar with our application. The build file for clusteredChat2 already does this for you.
4. Modify ChatRoom.java.
The ChatRoom class provides the bulk of the logic for the application. It interacts with the database to store and retrieve both users and messages as well as triggering server-initiated renders when something is updated. There are a couple of simple changes needed to take advantage of clustered rendering.
First, we have to modify the setter method for the RenderManager to accept the BroadcastRenderManager to match our change in the faces-config.xml file. So this:
public void setRenderManager(RenderManager renderManager) {
 
	 roomRenderer = renderManager.getOnDemandRenderer(ROOM_RENDERER_NAME);
 
}
 
becomes:
public void setRenderManager(BroadcastRenderManager renderManager) {
 
	roomRenderer = renderManager.getOnDemandRenderer(ROOM_RENDERER_NAME);
 
	this.renderManager = renderManager;
 
}
 
We also store the reference to the BroadcastRenderManager so that we can call relayRenderRequest when needed.
private BroadcastRenderManager renderManager;
 
To use the BroadcastRenderManager, it should be imported.
import com.icesoft.faces.async.render.broadcast.BroadcastRenderManager;
 
The only other change is in the addEntry method. This is the method that adds new messages to the database whenever a user joins/leaves or when a chat message is sent. In the clusteredChat1, the method looks like this:
public void addEntry(Message message) {
 
        if (log.isTraceEnabled()) {
 
            log.trace(message.getFormattedMessage());
 
        }
 
        db.addRow(DBUtil.MESSAGES_TABLE,
 
                DBUtil.MESSAGE_COLUMN,
 
                message.getFormattedMessage());
 

 
        roomRenderer.requestRender();
 
}
 

The roomRenderer is a group renderer that holds a collection of all the active users in the application. Whenever a new message is added, we request a render on that group and everyone gets updated, pulling the new information out of the database. In clusteredChat2, the method is modified as follows:

public void addEntry(Message message) {
 
        if (log.isTraceEnabled()) {
 
            log.trace(message.getFormattedMessage());
 
        }
 
        db.addRow(DBUtil.MESSAGES_TABLE,
 
                DBUtil.MESSAGE_COLUMN,
 
                message.getFormattedMessage());
 

 
//        roomRenderer.requestRender();
 
        renderManager.relayRenderRequest(ROOM_RENDERER_NAME);
 
}
 

Rather than calling requestRender() on the roomRenderer, we now broadcast a message to all the nodes in the cluster that a render request has been made for the chat room of which, in our application, there is only one. All the nodes in the cluster receive this message, including the one that sent it, so we disable the requestRender call to avoid an extra local render. Each BroadcastRenderManager that receives the message will look up the named group renderer and call its requestRender() method.

That's all the changes for converting clusteredChat1 to clusteredChat2. You can try building and deploying the application as described for clusteredChat1, then try the same test. You should be able to see that render requests are now traveling across the nodes in the cluster and updating all the active chat clients appropriately.



Copyright 2005-2006. ICEsoft Technologies, Inc.
http://www.icesoft.com

TOC PREV NEXT INDEX