JBoss AS 7 HA tutorial

Please note: This tutorial has been written for JBoss AS 7 / EAP 6
If you want to read the latest articles about JBoss / WildFly HA please check the following:

Configuring High Availability with WildFly
JBoss Clustering a Web Application
Clustering EJB 3 with JBoss AS

In this tutorial we will show how to achieve High Availability with your Enterprise Java Beans using a simple Stateful clustered EJB and a remote Client.

Clustering stateful session beans requires JBoss AS to manage the state information. The component that is in charge to manage state information is Infinispan, which by default uses Replication to keep the session synchronized between components, each time the state of a bean changes.

In this tutorial we will set up and test a standalone cluster made up of two nodes and we will deploy our Stateful EJB on both nodes, by simply dropping the artifact on the deployments folder. Here’s a picture of our cluster definition:

cluster jboss high availability ha tutorial cluster

Now let’s code a Simple SFSB with a counter variable instance that will be used to keep track of the session:

package com.sample.ejb;

import javax.annotation.PostConstruct;
import javax.ejb.Remote;
import javax.ejb.Stateful;
import org.jboss.ejb3.annotation.Clustered;


@Stateful
@Clustered

@Remote(SampleBeanRemote.class) 
public class  SampleBeanRemoteImpl implements SampleBeanRemote  {
    int counter=0;

    @PostConstruct
    public void init() {
           System.out.println("EJB inited!");
    }


    @Override
    public int sum() {

               counter++;
               System.out.println("Value of the counter:"+counter);
               return counter;
    }


}

And here’s the corresponding SampleBeanRemote interface:

package com.sample.ejb;

public interface SampleBeanRemote {
    public int sum();

}
Important Notice

If you are using Eclipse and JBoss Tools (3.3) the JBoss AS 7 Server library does not includes by default the libraries where the @Clustered annotation is contained. Until this issue is solved, you have to include the jboss-ejb3-ext-api-2.0.0.jar manually as shown by the following picture:

jboss cluster tutorial software

On the other hand, if you are using Maven to build your project, you need to add the following dependency in order to compile your Clustered EJB:

<dependency>
            <groupId>org.jboss.ejb3</groupId>
            <artifactId>jboss-ejb3-ext-api</artifactId>
            <version>2.0.0</version>
</dependency>

Fine, now start your cluster with a cluster-aware configuration as in the following example:

NodeA

standalone -c standalone-ha.xml -Djboss.node.name=nodeA                    

NodeB

standalone -c standalone-ha.xml -Djboss.socket.binding.port-offset=200 -Djboss.node.name=nodeB

And deploy your EJB application to both nodes of your cluster (simply copy them in the deployments folder, if you are using a standalone cluster)

Now it’s time to code your client application which will invoke the sum() method and display the value for that field.

package com.sample.client;

import javax.naming.*;

import com.sample.ejb.SampleBeanRemote;
import com.sample.ejb.SampleBeanRemoteImpl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;


public class RemoteEJBClient {

    public static void main(String[] args) throws Exception {
        testRemoteEJB();

    }

    private static void testRemoteEJB() throws NamingException {

        final SampleBeanRemote ejb = lookupRemoteEJB();
        int s = ejb.sum();

        System.out.println("Value of Counter " +s);

        s = ejb.sum();

        System.out.println("Value of Counter " +s);

        System.out.println("Shut down the pinned JBoss AS 7 node and press ENTER");

        pressAKey();

        s = ejb.sum();

        System.out.println("Value of Counter " +s);
    }

    private static SampleBeanRemote lookupRemoteEJB() throws NamingException {
        final Hashtable jndiProperties = new Hashtable();
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");

        final Context context = new InitialContext(jndiProperties);


        final String appName = "";
        final String moduleName = "jboss-as-ejb-remote-app";
        final String distinctName = "";
        final String beanName = SampleBeanRemoteImpl.class.getSimpleName();

        final String viewClassName = SampleBeanRemote.class.getName();
        System.out.println("Looking EJB via JNDI ");
        System.out.println("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);

        return (SampleBeanRemote) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName+"?stateful");


    }


    // Compatible with Eclipse Environment
    public static void pressAKey() {

        InputStreamReader istream=null;

        BufferedReader bufRead=null;


        istream = new InputStreamReader(System.in) ;

        bufRead = new BufferedReader(istream) ;

        String returnval = null;
        try {
            returnval =  bufRead.readLine();
            bufRead.close();
            istream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

As you can see, after the second invocation, you need to press the ENTER key, so you are allowed to shut down the JBoss AS 7 instance which is pinned to our client and see if the session is correctly moved to the other node.

Last thing we need adding is the jboss-ejb-client.properties which will contain the list of nodes which will be used by the client application. (Since the second node is running with a port-offset of 200m the remoting node port will be 4647)

remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false

remote.connections=node1,node2

remote.connection.node1.host=localhost
remote.connection.node1.port = 4447
remote.connection.node1.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.node1.username=userejb
remote.connection.node1.password=userejb123

 

remote.connection.node2.host=localhost
remote.connection.node2.port = 4647
remote.connection.node2.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false
remote.connection.node2.username=userejb
remote.connection.node2.password=userejb123

Ready to run !
Launch the client application and verify on the console that the EJB correctly prints out the total:

cluster jboss high availability jboss as 7

Now kill this server instance (Control-C on the window will suffice), and press the ENTER key in your Client shell.

cluster jboss tutorial cluster HA high availability

Et voilà ! The clustered session has been recovered by the other server node. In the next tutorial we will check high availability using a clustered Web application.