Stateful Session Bean State Management Example

Environment Used

  • JDK 6 (Java SE 6)
  • EJB 3.x Stateful Session Bean
  • Eclipse Indigo IDE for Java EE Developers (3.7.1)
  • JBoss Tools – Core 3.3.0 M5 for Eclipse Indigo (3.7.1)
  • JBoss Application Server (AS) 7.1.0 Final

Setting up development environment:
Read this page for installing and setting up the environment for developing and deploying EJB 3.x on JBoss application server.

Project Description

  • This tutorial explains how the EJB container manages state information of a stateful session bean.
  • We show that the container assigns the same instance to the client on multiple invocations
  • This example explains how to develop, deploy and run this application in JBoss application server.
  • For testing this example we create a remote Java Application Client (main()) which is created in the same project as session bean.
  • Refer this tutorial page for more detailed explanation on stateful session bean state management.

Project Folder Structure

The figure below shows the final directory structure of this example.

Bean Business Interface

package com.ibytecode.business;
import javax.ejb.Remote;

@Remote
public interface Account {

	void deposit(double amount);
	String printAccountDetails();
	public String getName();
	public void setName(String name);
	public double getBalance();
	public void setBalance(double balance);
}

Bean Implementation Class

Create the bean implementation class.

package com.ibytecode.businesslogic;

import com.ibytecode.business.Account;
import javax.ejb.Stateful;

@Stateful
public class AccountBean implements Account {
	private String name = "Default";
	private double balance = 50;
	
   	public AccountBean() {}

	public void deposit(double amount) {
		balance = balance + amount;		
	}

	public String printAccountDetails() {
		return "Account [name=" + name + ", balance=" + balance + "]";
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getBalance() {
		return balance;
	}
	public void setBalance(double balance) {
		this.balance = balance;
	}
}

Java Application Client

Client Utility class (JNDILookupClass) for JBoss AS 7.1

package com.ibytecode.clientutility;

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

public class JNDILookupClass {

	private static Context initialContext;
	private static final String PKG_INTERFACES = "org.jboss.ejb.client.naming";

	public static Context getInitialContext() throws NamingException {
		if (initialContext == null) {
			Properties properties = new Properties();
			properties.put(Context.URL_PKG_PREFIXES, PKG_INTERFACES);

			initialContext = new InitialContext(properties);
		}
		return initialContext;
	}
}

Client

package com.ibytecode.client;

import javax.naming.Context;
import javax.naming.NamingException;

import com.ibytecode.business.Account;
import com.ibytecode.businesslogic.AccountBean;
import com.ibytecode.clientutility.JNDILookupClass;

public class AccountBeanClient implements Runnable{
	public static void main(String[] args) {
		AccountBeanClient obj1 = new AccountBeanClient();
		for(int i = 0 ; i < 10; i++) {
			Thread t1 = new Thread(obj1, "T" + i);
			t1.start();
		}
	}

	public void run() {
		Account bean = doLookup();
		// 1. Setting name and balance
		bean.setName(Thread.currentThread().getName());
		bean.setBalance(Math.ceil(Math.random() * 10000));
		
		// 1. Reading the state of the bean for the first time
		System.out.println(Thread.currentThread().getName() + 
				" -> Reading Name : " + bean.getName());
		System.out.println(Thread.currentThread().getName() + 
				" -> Reading Balance : " + bean.getBalance());
		System.out.println(Thread.currentThread().getName() + 
				" " + bean.printAccountDetails());
	}

	private static Account doLookup() {
		Context context = null;
		Account bean = null;
		try {
			// 1. Obtaining Context
			context = JNDILookupClass.getInitialContext();
			// 2. Generate JNDI Lookup name
			String lookupName = getLookupName();
			// 3. Lookup and cast
			bean = (Account) context.lookup(lookupName);

		} catch (NamingException e) {
			e.printStackTrace();
		}
		return bean;
	}

	private static String getLookupName() {
		/*
		 * The app name is the EAR name of the deployed EJB without .ear suffix.
		 * Since we haven't deployed the application as a .ear, the app name for
		 * us will be an empty string
		 */
		String appName = "";

		// The module name is the JAR name of the deployed EJB without the .jar
		// suffix.
		String moduleName = "StatelessSessionBean";

		/*
		 * AS7 allows each deployment to have an (optional) distinct name. This
		 * can be an empty string if distinct name is not specified.
		 */
		String distinctName = "";

		// The EJB bean implementation class name
		String beanName = AccountBean.class.getSimpleName();

		// Fully qualified remote interface name
		final String interfaceName = Account.class.getName();

		// Create a look up string name
		String name = "ejb:" + appName + "/" + moduleName + "/" + distinctName
				+ "/" + beanName + "!" + interfaceName + "?stateful";

		return name;
	}
}

We use JBoss AS 7.1 and EJB3.1 look up naming convention.

If the application server uses EJB3 look up naming convention, example JBoss AS 5 or 6 then the following lookup name should be used.
“AccountBean/remote”

T3 -> Reading Name : T3
T7 -> Reading Name : T7
T9 -> Reading Name : T9
T5 -> Reading Name : T5
T3 -> Reading Balance : 2371.0
T8 -> Reading Name : T8
T0 -> Reading Name : T0
T4 -> Reading Name : T4
T7 -> Reading Balance : 9477.0
T5 -> Reading Balance : 5811.0
T9 -> Reading Balance : 5560.0
T1 -> Reading Name : T1
T3 Account [name=T3, balance=2371.0] T8 -> Reading Balance : 4286.0
T2 -> Reading Name : T2
T0 -> Reading Balance : 8484.0
T4 -> Reading Balance : 9361.0
T1 -> Reading Balance : 2308.0
T9 Account [name=T9, balance=5560.0] T2 -> Reading Balance : 7886.0
T4 Account [name=T4, balance=9361.0] T0 Account [name=T0, balance=8484.0] T1 Account [name=T1, balance=2308.0] T8 Account [name=T8, balance=4286.0] T5 Account [name=T5, balance=5811.0] T7 Account [name=T7, balance=9477.0] T6 -> Reading Name : T6
T2 Account [name=T2, balance=7886.0] T6 -> Reading Balance : 2168.0
T6 Account [name=T6, balance=2168.0]

For a step by step tutorial on creating and deploying EJB project in
JBoss AS 7 -> refer this page.
JBoss AS 6 -> refer this page.
JBoss AS 5 -> refer this page.

Leave a Comment