Persisting an Object with EJB3.1

Hello to everyone, in my last post we have seen how to create a stateless session bean and call it from Java Client(Standalone Java code). Today in this post we are going to see how to call Entity Beans from a statefull session bean.

Stateful vs. Stateless Session Beans

A stateful session bean will maintain a conversational state with a client. The state of the session is maintained for the duration of the conversation between the client and the stateful session bean. When the client removes the stateful session bean, its session ends and the state is destroyed. The transient nature of the state of the stateful session bean should not be problematic for either the client or the bean, because once the conversation between the client and the stateful session bean ends, neither the client nor the stateful session bean should have any use for the state.

A stateless session bean will not maintain conversational states for specific clients longer than the period of an individual method invocation. Instance variables used by a method of a stateless bean may have a state, but only for the duration of the method invocation. After a method has finished running either successfully or unsuccessfully, the states of all its instance variables are dropped. The transient nature of this state gives the stateless session bean beneficial attributes, such as the following:

Bean pooling Any stateless session bean method instance that is not currently invoked is equally available to be called by an EJB container or application server to service the request of a client. This allows the EJB container to pool stateless bean instances and increase performance.

Scalability Because stateless session beans are able to service multiple clients, they tend to be more scalable when applications have a large number of clients. When compared to stateful session beans, stateless session beans usually require less instantiation.

Performance An EJB container will never move a stateless session bean from RAM out to a secondary storage, which it may do with a stateful session bean; therefore, stateless session beans may offer greater performance than stateful session beans.

Since no explicit mapping exists between multiple clients and stateless bean instances, the EJB container is free to service any client’s request with any available instance. Even though the client calls the create() and remove() methods of the stateless session bean, making it appear that the client is controlling the lifecycle of an EJB, it is actually the EJB container that is handling the create() and remove() methods without necessarily instantiating or destroying an EJB instance.

Now lets Dive into coding part
project structure looks as below

ProjStruct

in eclipse, create an EJB project, now lets start with our persistence.xml file which will act as communication between code and database. please create a datasource in JBoss AS 7.1 and assign it to persistenceUnit

META-INF/persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
	version="2.0">

	<persistence-unit name="MyPersistenceUnit"
		transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
		<jta-data-source>java:/mySqlDS</jta-data-source>
		<class>com.spark.ejb.entites.Employee</class>
		<properties>
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<property name="hibernate.show_sql" value="false" />
			<!-- <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
			<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
			<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test" />
			<property name="hibernate.connection.username" value="root" />
			<property name="hibernate.connection.password" value="root" /> -->

			<property name="hibernate.c3p0.min_size" value="5" />
			<property name="hibernate.c3p0.max_size" value="20" />
			<property name="hibernate.c3p0.timeout" value="300" />
			<property name="hibernate.c3p0.max_statements" value="50" />
			<property name="hibernate.c3p0.idle_test_period" value="3000" />

		</properties>

	</persistence-unit>
</persistence>

Now its time to create EntityManager object which is used to do db manipulations, lets create simple utility class which will return EntityManager object

package com.spark.ejb.persistence.context;

import javax.persistence.EntityManager;
import javax.persistence.Persistence;

/**
 * @author Sony
 *
 */
public class PersistenceContextFactory {

	static EntityManager entityManager = Persistence.createEntityManagerFactory("MyPersistenceUnit").createEntityManager();
	
	public static EntityManager getEntityManager(){
		return entityManager; 
	}
}

once we have entityManager Object lets start session beans and its interfaces as below.
EmployeeSessionBeanLocal.java

package com.spark.ejb.session.beans;

import java.util.List;

import javax.ejb.Local;

import com.spark.ejb.entites.Employee;

@Local
public interface EmployeeSessionBeanLocal {

	public void saveObject(Employee employee);
	public <T extends Object> T getObjectById(int id);
	public <T extends Object> List<T> getAllRecords();
}

EmployeeSessionBeanRemote.java

package com.spark.ejb.session.beans;

import java.util.List;

import javax.ejb.Remote;

import com.spark.ejb.entites.Employee;

@Remote
public interface EmployeeSessionBeanRemote {

	public void saveObject(Employee employee);
	public <T extends Object> T getObjectById(int id);
	public <T extends Object> List<T> getAllRecords();
}

EmployeeSessionBean.java

package com.spark.ejb.session.beans;

import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Remote;
import javax.ejb.Stateful;
import javax.ejb.StatefulTimeout;
import javax.enterprise.context.SessionScoped;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.spark.ejb.entites.Employee;
import com.spark.ejb.persistence.context.PersistenceContextFactory;
import com.spark.ejb.transactions.EmployeeTransactionUnit;

/**
 * Session Bean implementation class EmployeeSessionBean
 */
@Stateful
@SessionScoped
@StatefulTimeout(unit = TimeUnit.MINUTES, value = 10)
@Remote(EmployeeSessionBeanRemote.class)
public class EmployeeSessionBean implements EmployeeSessionBeanRemote, EmployeeSessionBeanLocal {

	EmployeeTransactionUnit employeeTransactionUnit;
	Logger logger = LoggerFactory.getLogger(EmployeeSessionBean.class);
	
	@PostConstruct
	public void afterConstruct(){
		logger.info("--------------------- after construct is called --------------------");
		employeeTransactionUnit = new EmployeeTransactionUnit();
		logger.info("--------------------- employee transaction class instantiated --------------------");
	}
	
	@PostActivate
	public void postActivate(){
		logger.info("--------------------- post activate is called --------------------");
	}
	
    @PreDestroy
    public void preDestroy(){
    	logger.info("---------------- pre destroy called --------------------");
    }
    
    @PrePassivate
    public void prePassivate(){
    	logger.info("---------------- pre passivate called --------------------");
    }

	@Override
	public void saveObject(Employee employee) {
		logger.info("------------------ before calling persist method ---------------------");
		employeeTransactionUnit.persistObject(PersistenceContextFactory.getEntityManager(),employee);
	}
	
	public <T extends Object> T getObjectById(int id){
		return employeeTransactionUnit.getObjectById(PersistenceContextFactory.getEntityManager(), id);
	}
	
	public <T extends Object> List<T> getAllRecords(){
		return employeeTransactionUnit.getAllRecords(PersistenceContextFactory.getEntityManager());
	}

}

at this point lets talk little bit on the above statefull bean, we can specify various life cycle methods using their annotations like (pre passivate,post activate) and we can even specify the bean timeout for the statefull session bean to be in the bean pool, after that it will be passivated and removed from memory by the EJB container.

lets have a look at our entity bean as follows.

/**
 * 
 */
package com.spark.ejb.entites;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 * @author Sony
 * 
 */

@Entity
@Table(name = "employee")
@NamedQueries({
@NamedQuery(name="Employee.getAllRecords",
    query="SELECT e FROM Employee e")          
})
public class Employee implements Serializable,Comparable<Employee> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "EmployeeID")
	private int id;
	
	@Column(name = "FirstName")
	private String firstName;
	@Column(name = "LastName")
	private String lastName;
	@Column(name = "Title")
	private String title;
	@Column(name = "TitleOfCourtesy")
	private String titleOfCourtesy;

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id
	 *            the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	/**
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * @param lastName
	 *            the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title
	 *            the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}

	/**
	 * @return the titleOfCourtesy
	 */
	public String getTitleOfCourtesy() {
		return titleOfCourtesy;
	}

	/**
	 * @param titleOfCourtesy
	 *            the titleOfCourtesy to set
	 */
	public void setTitleOfCourtesy(String titleOfCourtesy) {
		this.titleOfCourtesy = titleOfCourtesy;
	}

	 public int compareTo(Employee obj) {
	        int lastCmp = lastName.compareTo(obj.lastName);
	        return (lastCmp != 0 ? lastCmp : firstName.compareTo(obj.firstName));
	    }
}

In the above entity bean code observe that i have implemented Comparable interface, so that i can have sorting of different records once i retrieve from database.

Now lets see our transaction unit as follows.
note: please observer carefully various generics that i have used to make the code work more generic

/**
 * 
 */
package com.spark.ejb.transactions;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.spark.ejb.entites.Employee;

/**
 * @author Sony
 * 
 */
public class EmployeeTransactionUnit {

	// @PersistenceContext(name="MyPersistenceUnit")
	// EntityManager entityManager;

	Logger logger = LoggerFactory.getLogger(EmployeeTransactionUnit.class);
	
	public <T extends Object> void persistObject(
			EntityManager entityManager, T object) {
		
		EntityTransaction entityTransaction = entityManager.getTransaction();
		try {
			logger.info("------------------ getting transaction object ---------------------");
			entityTransaction.begin();
			logger.info("------------------ using transaction object to persist ---------------------");
			entityManager.persist(object);
			logger.info("------------------ object persisted to database ---------------------");
			entityTransaction.commit();
			logger.info("------------------ transaction committed ---------------------");
		} catch (Exception e) {
			entityTransaction.rollback();
			logger.info("------------------ Exception while transaction ---------------------"+e.getMessage());
		}

	}
	
	@SuppressWarnings("unchecked")
	public <T extends Object> T getObjectById(EntityManager entityManager, int id){
		logger.info("------------------ entity manager to load the object by id ---------------------");
		Employee employee = entityManager.find(Employee.class, id);
		logger.info("------------------ object retrieved ---------------------");
		return (T)employee;
	}
	
	@SuppressWarnings("unchecked")
	public <T extends Object> List<T> getAllRecords(EntityManager entityManager){
		logger.info("------------------ entity manager to load all objects ---------------------");
		Query query = entityManager.createNamedQuery("Employee.getAllRecords");
		List<T> t = query.getResultList();
		logger.info("------------------ list of objects retrieved ---------------------");
		return t;
	}
}



that is it guys our ejb is ready, go head and deploy in JBoss AS 7.1. now its time for us to write a client to test this.

/**
 * 
 */
package com.spark.ejb.client;

import java.util.Properties;

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

/**
 * @author Sony
 *
 */
public class ClientUtility {

	private static Context initialContext;
    private static final String PKG_INTERFACE = "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_INTERFACE);
             
            initialContext = new InitialContext(properties);
        }
        return initialContext;
    }
}

/**
 * 
 */
package com.spark.ejb.client;

import java.util.Collections;
import java.util.List;

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

import com.spark.ejb.entites.Employee;
import com.spark.ejb.session.beans.EmployeeSessionBean;
import com.spark.ejb.session.beans.EmployeeSessionBeanRemote;

/**
 * @author Sony
 * 
 */
public class EJBClient {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		EmployeeSessionBeanRemote bean = doLookUp();
		
		Employee employee = new Employee();
		employee.setFirstName("Venkata Subramanya Deepak");
		employee.setLastName("Mantha");
		employee.setTitle("Scientific Office D");
		employee.setTitleOfCourtesy("Mr");
		
		//bean.saveObject(employee);
		Employee employee2 = bean.getObjectById(11);
		System.out.println(employee2.getTitleOfCourtesy()+" "+employee2.getFirstName()+" "+employee2.getLastName());
		
		List<Employee> list = bean.getAllRecords();
		Collections.sort(list);
		
		for(Employee employee3 : list){
			System.out.println(employee3.getLastName()+" "+employee3.getFirstName());
		}
		
	}

	private static EmployeeSessionBeanRemote doLookUp() {
		Context context = null;
		EmployeeSessionBeanRemote bean = null;
		try {
			// 1. Obtaining Context
			context = ClientUtility.getInitialContext();
			// 2. Generate JNDI Lookup name
			String lookupName = getLookUpName();
			// 3. Lookup and cast
			bean = (EmployeeSessionBeanRemote) context.lookup(lookupName);

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

	private static String getLookUpName() {

		// AppName is the .ear file name without extension, if no .ear is
		// deployed then this is empty
		String appName = "";

		// module name is the EJB jar file deployed without .jar extension
		String moduleName = "EJBCRUDProject";

		String distinctName = "";

		// EJB bean impl class name
		String beanName = EmployeeSessionBean.class.getSimpleName();

		// Fully qualified remoteInterface Name
		String interfaceName = EmployeeSessionBeanRemote.class.getName();

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

		return name;
	}
}

once you run the client you should be able to see similar kind of output on the server console.

output

note: i did not code the update logic its left for you people to do it.

Happy Session Beans and Entity Beans 🙂 Happy EJB 🙂