Featured Post

Event Sourcing Video from Michael Ploed

Event Sourcing I want to share a great video I found few days ago that describes very well what Event Sourcing is.

Sunday, September 2, 2012

Stateful Session Bean Clustered - Tutorial

In this post I'll show an example of a Stateful Sesson Bean Clustered that implements a simple counter.
In a few steps we'll see how to configure a load balancer with Apache HTTP Server using Session Affinity on two JBoss nodes. Then we'll see the behaviour of the implemented Session Bean after a simulated failover: when one of the JBoss nodes fails, the Session will be replicated on the other active JBoss node.

Step-1: Configure Apache HTTP Server

First we have to configure the files <APACHE-HOME>/conf/workers.properties and <APACHE-HOME>/conf/httpd-vhosts.conf.

# Define list of workers that will be used
# for mapping requests

# Define Node1
# modify the host as your host IP or DNS name.

# Define Node2
# modify the host as your host IP or DNS name.
worker.node2.host= node2.counter.cluster.com

# Load-balancing behaviour

# Status worker for managing load balancer

<VirtualHost *:80>
  DocumentRoot “/local/docroot/htdocs”
  Include conf/tuo.conf
  JkMount /cluster/* loadbalancer

Step-2: Startup of the JBoss nodes

We have to startup the two JBoss instances that are on the same subnet (to make it simple).

Startup of JBoss node on address

./run.sh -c  all  -b -Djboss.messaging.ServerPeerID=1

Startup of JBoss node on address

./run.sh -c  all  -b -Djboss.messaging.ServerPeerID=2

Wait the two nodes start communicating each other

11:52:10,764 INFO  [DefaultPartition] New cluster view for partition DefaultPartition (id: 1, delta: 1) : [,]
11:52:10,766 INFO  [DefaultPartition] I am ( received membershipChanged event:
11:52:10,767 INFO  [DefaultPartition] Dead members: 0 ([])
11:52:10,767 INFO  [DefaultPartition] New Members : 1 ([])
11:52:10,767 INFO  [DefaultPartition] All Members : 2 ([,])
11:52:10,890 INFO  [RPCManagerImpl] Received new cluster view: [|1] [,]
11:52:22,027 INFO  [GroupMember] org.jboss.messaging.core.impl.postoffice.GroupMember$ControlMembershipListener@4d16c81d got new view [|1] [,], old view is [|0] []
11:52:22,028 INFO  [GroupMember] I am (
11:52:22,028 INFO  [GroupMember] New Members : 1 ([])
11:52:22,028 INFO  [GroupMember] All Members : 2 ([,])

As you can see the two instances has found each other and communicates with JGroup protocol. Afterwards this communication the cluster consists of two instances: Received new cluster view: [|1] [,].

Step-3: Write the Statefull Session Bean Clustered

We have to write a simple Session Stateful Bean that uses an instance variable called count. This counter is incremented on each call to the enterprise method.


import javax.ejb.Remote;

public interface CounterServiceRemote {
 public void increase();


import javax.ejb.Stateful;

import org.jboss.ejb3.annotation.Clustered;

 * Session Bean implementation class CounterService
public class CounterService implements CounterServiceRemote{

    private int count=0;
    public CounterService() {
    public void increase(){


Step-4: Deploy the jar containing the EJB in both the JBoss nodes

You have to put the jar into the directory <JBOSS-NODE>/server/all/deploy.

Step-5: Wait the deploy to be completed

Console Output

12:33:50,115 INFO  [JndiSessionRegistrarBase] Binding the following Entries in G
lobal JNDI:

        CounterService/remote - EJB3.x Default Remote Business Interface
        CounterService/remote-com.clusterproject.CounterServiceRemote - EJB3.x R
emote Business Interface

12:33:50,205 INFO  [PlatformMBeanServerRegistration] JBossCache MBeans were succ
essfully registered to the platform mbean server.
12:33:50,225 INFO  [STDOUT]

Step-6: Verify in the JMX console that the Stateful Session Bean is registered

Step-7: Verify in the JMX console that the cluster is online

Step-8: Run the EJB client



import javax.naming.NamingException;
import com.clusterproject.CounterServiceRemote;

public class ClientEJB {

   public static void main(String[] args) {
 try {
  Object obj =           
  CounterServiceRemote counterServiceRemote =(CounterServiceRemote) obj;
 } catch (NamingException e) {
 } catch (InterruptedException e) {


import java.util.Properties;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class ServiceLocator {

 public static Context getInitialContext(){
  Properties properties =new Properties();
  properties.put(Context.PROVIDER_URL, "jnp://counter.cluster.com:1099");
  InitialContext jndiContext=null;
  try {
   jndiContext=new InitialContext(properties);
  } catch (NamingException e) {
  return jndiContext;

It's important to notice that:
  • The instruction Thread.sleep(10000) is useful to wait the simulated fault of JBoss node;
  • The address counter.cluster.com is the jnp address of the load balancer machine. The EJB client has to know the address of the balancer machine.
After running the EJB client the below message will be written by the JBoss node that will serve the request.

INFO  [STDOUT] counter:0
INFO  [STDOUT] counter:1

Step-9:Shutdown of the serving JBoss node

During the waiting caused by Thread.sleep(10000), we have to shutdown the serving JBoss node. In this example I have used the JBoss instance on

After the shutdown completes, the active JBoss node will continue serving the request. As you can see in the following console lines:
  • Dead members: 1 ([])
  • All Members : 1 ([])


12:38:36,377 INFO  [RPCManagerImpl] Received new cluster view: [ |6] []
12:38:36,577 INFO  [GroupMember] org.jboss.messaging.core.impl.postoffice.GroupM
ember$ControlMembershipListener@191a87d got new view [|10] [], old view is [|9] [,]
12:38:36,577 INFO  [GroupMember] I am (
12:38:36,587 INFO  [GroupMember] Dead members: 1 ([])
12:38:36,587 INFO  [GroupMember] All Members : 1 ([])
12:38:37,779 INFO  [RPCManagerImpl] Received new cluster view: [|
10] []
12:38:37,849 INFO  [DefaultPartition] New cluster view for partition DefaultPart
ition (id: 10, delta: -1) : []
12:38:37,849 INFO  [DefaultPartition] I am ( received membership
Changed event:
12:38:37,849 INFO  [DefaultPartition] Dead members: 1 ([])
12:38:37,849 INFO  [DefaultPartition] New Members : 0 ([])
12:38:37,859 INFO  [DefaultPartition] All Members : 1 ([])
12:38:39,211 INFO  [STDOUT] counter:1
12:38:39,211 INFO  [STDOUT] counter:2
12:38:49,245 INFO  [STDOUT] counter:2
12:38:49,245 INFO  [STDOUT] counter:3

In summary this is only a simple rough example of a Clustered Session Bean, but I hope this post has arouse your curiosity about this subject.

No comments :

Post a Comment