Introduction to Enterprise JavaBeans 3.0

by Lynn Munsinger

The EJB 3.0 specification makes it easier than ever to develop Enterprise JavaBeans, perhaps encouraging you to consider developing EJBs for the first time. If that is the case, congratulations, you have successfully avoided the many pitfalls of EJB developers before you, and can enjoy the ease of EJB 3.0 development. But before you start development, you might want to know what Enterprise JavaBeans are and what purpose they serve. This article explains the basics of EJBs and how you can utilize them in a J2EE application.

What is an EJB?

An Enterprise JavaBean (EJB) is a reusable, portable J2EE component. EJBs consist of methods that encapsulate business logic. For example, an EJB may have business logic that contains a method to update customer data in a database. A variety of remote and local clients can invoke this method. Additionally, EJBs run inside a container, allowing the developer to focus on the business logic contained in the bean without having to worry about complicated and error-prone issues such as transaction support, security, and remote object access. EJBs are developed as POJOs, or Plain Old Java Objects, and developers can use metadata annotations to specify to the container how these beans are to be managed.

Types of EJBs

EJBs consist of three main types: Session, Entity, and Message-Driven. A Session bean performs a distinct, de-coupled task, such as checking credit history for a customer. An Entity bean is a complex business entity which represents a business object that exists in the database. A Message-Driven bean is used to receive asynchronous JMS messages. Let's examine these types further:

Session Beans

Session beans generally represent actions in the business process such as "process order." Session beans are classified based on the maintenance of the conversation state, either stateful or stateless.

Stateless session beans do not have an internal state. They do not keep track of the information that is passed from one method call to another. Thus, each invocation of a stateless business method is independent of its previous invocation; for example, calculating taxes or shipping charges. When a method to calculate tax charges is invoked with a certain taxable value, the tax value is calculated and returned to the calling method, without the necessity to store the caller's internal state for future invocation. Because they do not maintain state, these beans are simple to manage for the container. When the client requests a stateless bean instance, it may receive an instance from the pool of stateless session bean instances that are maintained by the container. Also, because stateless session beans can be shared, the container can maintain a lesser number of instances to serve a large number of clients. To specify that a Java Bean is to be deployed and managed as a stateless session bean, simply add the annotation @Stateless to the bean.

A stateful session bean maintains a conversational state across method invocations; for example, an online shopping cart of a customer. When the customer starts online shopping, the customer's details are retrieved from the database. The same details are available for the other methods that are invoked when the customer adds or removes items from the cart, places the order, and so on. Yet, stateful session beans are transient because the state does not survive session termination, system crash, or network failure. When a client requests a stateful session bean instance, that client is assigned one stateful instance, and the state of the bean is maintained for that client. To specify to the container that a stateful session bean instance should be removed upon the completion of a certain method, add the annotation @Remove to the method.

Session Bean Example

import javax.ejb.Stateless.*;

/**
* A simple stateless session bean implementing the incrementValue() method of the * CalculateEJB interface.
*/

@Stateless(name="CalculateEJB")
public class CalculateEJBBean
implements CalculateEJB
{
int value = 0;
public String incrementValue()
{
value++;
return "value incremented by 1";
}
}

 

Entity Beans

An entity bean is an object that manages persistent data, potentially uses several dependent Java objects, and can be uniquely identified by a primary key. Specify that a class is an entity bean by including the @Entity annotation. Entity beans represent persistent data from the database, such as a row in a customer table, or an employee record in an employee table. Entity beans are also sharable across multiple clients. For example, an employee entity bean can be used by various clients to calculate the annual salary of an employee or to update the employee address. Specific fields of the entity bean object can be made persistent. All fields in the entity bean not marked with the @Transient annotation are considered persistent. A key feature of EJB 3.0 is the ability to create Entity beans which contain object/relational mappings using metadata annotations. For example, to specify that an Entity bean's empId field is mapped to the EMPNO attribute of the Employees table, annotate the table name using @Table(name="Employees") and the field using @Column(name="EMPNO"), as shown in the example below. Additionally, a special feature of EJB 3.0 is that you can easily test Entity beans during development, as running Entity beans outside a container is now possible using the Oracle Application Server Entity Test Harness.

Entity Bean Example

import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collection;

@Entity
@Table(name = "EMPLOYEES")
public class Employee implements java.io.Serializable
{
private int empId;
private String eName;
private double sal;

@Id
@Column(name="EMPNO", primaryKey=true)
public int getEmpId()
{
return empId;
}

public void setEmpId(int empId)
{
this.empId = empId;
}

public String getEname()
{
return eName;
}

public void setEname(String eName)
{
this.eName = eName;
}

public double getSal()
{
return sal;
}


public void setSal(double sal)
{
this.sal = sal;
}

public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append("Class:")
.append(this.getClass().getName()).append(" :: ").append(" empId:").append(getEmpId()).append(" ename:").append(getEname()).append("sal:").append(getSal());
return buf.toString();
}
}

 

Message-Driven Beans

Message-driven beans (MDBs) provide an easier method to implement asynchronous communication than by using straight Java Message Services (JMS). MDBs were created to receive asynchronous JMS messages. The container handles most of the setup processes that are required for JMS queues and topics. It sends all the messages to the interested MDB. An MDB allows J2EE applications to send asynchronous messages that can then be processed by the application. To specify that a bean is an MDB, implement the javax.jms.MessageListener interface and annotate the bean with @MessageDriven.

Message Driven Bean Example

import javax.ejb.MessageDriven;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.Inject;
import javax.jms.*;
import java.util.*;
import javax.ejb.TimedObject;
import javax.ejb.Timer;
import javax.ejb.TimerService;
@MessageDriven(
activationConfig = {
@ActivationConfigProperty(propertyName="connectionFactoryJndiName", propertyValue="jms/TopicConnectionFactory"),
@ActivationConfigProperty(propertyName="destinationName", propertyValue="jms/myTopic"),
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Topic"),
@ActivationConfigProperty(propertyName="messageSelector", propertyValue="RECIPIENT = 'MDB'")

}
)

/**
* A simple Message-Driven Bean that listens to the configured JMS Queue or Topic and gets notified via an * invocation of it's onMessage() method when a message has been posted to the Queue or Topic. The bean
*
prints the contents of the message.
*/

public class MessageLogger implements MessageListener, TimedObject
{

@Inject javax.ejb.MessageDrivenContext mc;

public void onMessage(Message message)
{
System.out.println("onMessage() - " + message);
try
{
String subject = message.getStringProperty("subject");
String inmessage = message.getStringProperty("message");
System.out.println("Message received\n\tDate: " + new java.util.Date() + "\n\tSubject: " + subject + "\n\tMessage: " + inmessage + "\n");
System.out.println("Creating Timer a single event timer");
TimerService ts = mc.getTimerService();
Timer timer = ts.createTimer(30000, subject);
System.out.println("Timer created by MDB at: " + new Date(System.currentTimeMillis()) +" with info: "+subject);
}
catch (Throwable ex)
{
ex.printStackTrace();
}
}

public void ejbTimeout(Timer timer)
{
System.out.println("EJB 3.0: Timer with MDB");
System.out.println("ejbTimeout() called at: " + new Date(System.currentTimeMillis()));
return;
}

}

 

Utilizing EJBs

An EJB client is the application that accesses the bean. It does not necessarily reside on the client tier, but can be a stand-alone application, JSP, servlet, or another EJB. The client accesses the methods of an EJB through the remote or local interfaces of the bean, depending on whether the client resides in the same or a different JVM than the bean. These interfaces define the methods of the bean, while the bean class actually implements the methods. When a client accesses a method of the bean class, the container generates a proxy for the bean, called the remote or local object. The remote or local object receives the request, delegates it to the corresponding bean instance, and returns the results to the client. To invoke a bean's methods, a client finds the bean by using its name defined in the EJB deployment descriptor. In the following example, the client finds the bean named "Statelessejb" using the Context object.

EJB Client Example

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

/**
* A simple bean client which calls methods on a stateless session bean.
*/

public class CalculateejbClient
{
public static void main(String [] args)
{
Context context = new InitialContext();

CalculateEJB myejb =
(CalculateEJB)context.lookup("java:comp/env/ejb/CalculateEJB");
myejb.incrementValue();
}
}

 

Summary

Developing Enterprise JavaBeans is significantly easier with the EJB 3.0 specification. The specification uses metadata annotations to define the type of bean and the methods exposed to the client. Thus, whether you are creating a session bean for executing a specific task or mapping a table to an entity bean for updating data, you can do so using plain Java objects and interfaces, and expose methods for clients by using annotations within the business methods. Now that you have an understanding of the basics of EJBs, refer to OTN's EJB 3.0 Resources Page for more information.