Enterprise JavaBeans

Exclusive offer: get 50% off this eBook here
Java EE 5 Development using GlassFish Application Server

Java EE 5 Development using GlassFish Application Server — Save 50%

The complete guide to installing and configuring the GlassFish Application Server and developing Java EE 5 applications to be deployed to this server

$29.99    $15.00
by David R. Heffelfinger | October 2007 | Java Open Source

Enterprise JavaBeans are server-side components that encapsulate application business logic. Enterprise JavaBeans simplify application development by automatically taking care of transaction management and security.

In this article, author David Heffelfinger explains the two types of Enterprise JavaBeans – Session Beans, which perform business logic; and Message-Driven Beans, which act as a message listener.

Readers familiar with previous versions of J2EE will notice that Entity Beans were not mentioned in the above paragraph. In Java EE 5, Entity Beans have been deprecated in favor of the Java Persistence API (JPA). Entity Beans are still supported for backwards compatibility; however, the preferred way of doing Object Relational Mapping with Java EE 5 is through JPA. Refer to Chapter 4 in the book Java EE 5 Development using GlassFish Application Server for a detailed discussion on JPA.

Session Beans

As we previously mentioned, session beans typically encapsulate business logic. In Java EE 5, only two artifacts need to be created in order to create a session bean: the bean itself, and a business interface. These artifacts need to be decorated with the proper annotations to let the EJB container know they are session beans.

Previous versions of J2EE required application developers to create several artifacts in order to create a session bean. These artifacts included the bean itself, a local or remote interface (or both), a local home or a remote home interface (or both) and a deployment descriptor. As we shall see in this article, EJB development has been greatly simplified in Java EE 5.

Simple Session Bean

The following example illustrates a very simple session bean:

    package net.ensode.glassfishbook;
import javax.ejb.Stateless;
@Stateless
public class SimpleSessionBean implements SimpleSession
{
private String message =
"If you don't see this, it didn't work!";
public String getMessage()
{
return message;
}
}

The @Stateless annotation lets the EJB container know that this class is a stateless session bean. There are two types of session beans, stateless and stateful. Before we explain the difference between these two types of session beans, we need to clarify how an instance of an EJB is provided to an EJB client application.

When EJBs (both session beans and message-driven beans) are deployed, the EJB container creates a series of instances of each EJB. This is what is typically referred to as the EJB pool. When an EJB client application obtains an instance of an EJB, one of the instances in the pool is provided to this client application.

The difference between stateful and stateless session beans is that stateful session beans maintain conversational state with the client, where stateless session beans do not. In simple terms, what this means is that when an EJB client application obtains an instance of a stateful session bean, the same instance of the EJB is provided for each method invocation, therefore, it is safe to modify any instance variables on a stateful session bean, as they will retain their value for the next method call.

The EJB container may provide any instance of an EJB in the pool when an EJB client application requests an instance of a stateless session bean. As we are not guaranteed the same instance for every method call, values set to any instance variables in a stateless session bean may be "lost" (they are not really lost; the modification is in another instance of the EJB in the pool).

Other than being decorated with the @Stateless annotation, there is nothing special about this class. Notice that it implements an interface called SimpleSession. This interface is the bean's business interface. The SimpleSession interface is shown next:

    package net.ensode.glassfishbook;
import javax.ejb.Remote;
@Remote
public interface SimpleSession
{
public String getMessage();
}

The only peculiar thing about this interface is that it is decorated with the @Remoteannotation. This annotation indicates that this is a remote business interface . What this means is that the interface may be in a different JVM than the client application invoking it. Remote business interfaces may even be invoked across the network.

Business interfaces may also be decorated with the @Local interface. This annotation indicates that the business interface is a local business interface. Local business interface implementations must be in the same JVM as the client application invoking their methods.

As remote business interfaces can be invoked either from the same JVM or from a different JVM than the client application, at first glance, we might be tempted to make all of our business interfaces remote. Before doing so, we must be aware of the fact that the flexibility provided by remote business interfaces comes with a performance penalty, because method invocations are made under the assumption that they will be made across the network. As a matter of fact, most typical Java EE application consist of web applications acting as client applications for EJBs; in this case, the client application and the EJB are running on the same JVM, therefore, local interfaces are used a lot more frequently than remote business interfaces.

Once we have compiled the session bean and its corresponding business interface,we need to place them in a JAR file and deploy them. Just as with WAR files, the easiest way to deploy an EJB JAR file is to copy it to [glassfish installationdirectory]/glassfish/domains/domain1/autodeploy.

Now that we have seen the session bean and its corresponding business interface, let's take a look at a client sample application:

    package net.ensode.glassfishbook;
import javax.ejb.EJB;
public class SessionBeanClient
{
@EJB
private static SimpleSession simpleSession;
private void invokeSessionBeanMethods()
{
System.out.println(simpleSession.getMessage());
System.out.println("nSimpleSession is of type: "
+ simpleSession.getClass().getName());
}
public static void main(String[] args)
{
new SessionBeanClient().invokeSessionBeanMethods();
}
}

The above code simply declares an instance variable of type net.ensode.SimpleSession, which is the business interface for our session bean. The instance variable is decorated with the @EJB annotation; this annotation lets the EJB container know that this variable is a business interface for a session bean. The EJB container then injects an implementation of the business interface for the client code to use. As our client is a stand-alone application (as opposed to a Java EE artifact such as a WAR file) in order for it to be able to access code deployed in the server, it must be placed in a JAR file and executed through the appclient utility. This utility can be found at [glassfish installation directory]/glassfish/bin/. Assuming this path is in the PATH environment variable, and assuming we placed our client code in a JAR file called simplesessionbeanclient.jar, we would execute the above client code by typing the following command in the command line:

  appclient -client simplesessionbeanclient.jar

Executing the above command results in the following console output:

  If you don't see this, it didn't work!

SimpleSession is of type: net.ensode.glassfishbook._SimpleSession_Wrapper

which is the output of the SessionBeanClient class.

The first line of output is simply the return value of the getMessage() method we implemented in the session bean. The second line of output displays the fully qualified class name of the class implementing the business interface. Notice that the class name is not the fully qualified name of the session bean we wrote; instead, what is actually provided is an implementation of the business interface created behind the scenes by the EJB container.

A More Realistic Example

In the previous section, we saw a very simple, "Hello world" type of example. In this section, we will show a more realistic example. Session beans are frequently used as Data Access Objects (DAOs). Sometimes, they are used as a wrapper for JDBC calls, other times they are used to wrap calls to obtain or modify JPA entities. In this section, we will take the latter approach.

The following example illustrates how to implement the DAO design pattern in asession bean. Before looking at the bean implementation, let's look at the business interface corresponding to it:

    package net.ensode.glassfishbook;
import javax.ejb.Remote;
@Remote
public interface CustomerDao
{
public void saveCustomer(Customer customer);
public Customer getCustomer(Long customerId);
public void deleteCustomer(Customer customer);
}

As we can see, the above is a remote interface implementing three methods; thesaveCustomer() method saves customer data to the database, the getCustomer()method obtains data for a customer from the database, and the deleteCustomer() method deletes customer data from the database. Let's now take a look at the session bean implementing the above business interface. As we are about to see, there are some differences between the way JPA code is implemented in a session bean versus in a plain old Java object.

    package net.ensode.glassfishbook;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
@Stateless
public class CustomerDaoBean implements CustomerDao
{
@PersistenceContext
private EntityManager entityManager;
@Resource(name = "jdbc/__CustomerDBPool")
private DataSource dataSource;
public void saveCustomer(Customer customer)
{
if (customer.getCustomerId() == null)
{
saveNewCustomer(customer);
}
else
{
updateCustomer(customer);
}
}
private void saveNewCustomer(Customer customer)
{
customer.setCustomerId(getNewCustomerId());
entityManager.persist(customer);
}
private void updateCustomer(Customer customer)
{
entityManager.merge(customer);
}
public Customer getCustomer(Long customerId)
{
Customer customer;
customer = entityManager.find(Customer.class, customerId);
return customer;
}
public void deleteCustomer(Customer customer)
{
entityManager.remove(customer);
}
private Long getNewCustomerId()
{
Connection connection;
Long newCustomerId = null;
try
{
connection = dataSource.getConnection();
PreparedStatement preparedStatement = connection
.prepareStatement(
"select max(customer_id)+1 as new_customer_id "
+ "from customers");
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet != null && resultSet.next())
{
newCustomerId = resultSet.getLong("new_customer_id");
}
connection.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
return newCustomerId;
}
}

The first difference we should notice is that an instance of javax.persistence. EntityManager is directly injected into the session bean. In previous JPA examples,we had to inject an instance of javax.persistence.EntityManagerFactory, then use the injected EntityManagerFactory instance to obtain an instance of EntityManager.

The reason we had to do this was that our previous examples were not thread safe. What this means is that potentially the same code could be executed concurrently by more than one user. As EntityManager is not designed to be used concurrently by more than one thread, we used an EntityManagerFactory instance to provide each thread with its own instance of EntityManager. Since the EJB container assigns a session bean to a single client at time, session beans are inherently thread safe, therefore, we can inject an instance of EntityManager directly into a session bean.

The next difference between this session bean and previous JPA examples is that in previous examples, JPA calls were wrapped between calls to UserTransaction.begin() and UserTransaction.commit(). The reason we had to do this is because JPA calls are required to be in wrapped in a transaction, if they are not in a transaction, most JPA calls will throw a TransactionRequiredException. The reason we don't have to explicitly wrap JPA calls in a transaction as in previous examples is because session bean methods are implicitly transactional; there is nothing we need to do to make them that way. This default behavior is what is known as Container-Managed Transactions. Container-Managed Transactions are discussed in detail later in this article.

When a JPA entity is retrieved in one transaction and updated in a different transaction, the EntityManager.merge() method needs to be invoked to update the data in the database. Invoking EntityManager.persist() in this case will result in a "Cannot persist detached object" exception.

Java EE 5 Development using GlassFish Application Server The complete guide to installing and configuring the GlassFish Application Server and developing Java EE 5 applications to be deployed to this server
Published: October 2007
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Invoking Session Beans from WebApplications

Frequently, Java EE applications consist of web applications acting as clients for EJBs. The most common way of deploying a Java EE application that consists of both a web application and one or more session beans is to package both the WAR file for the web application and the EJB JAR files into an EAR (Enterprise ARchive) file. In this section, we will modify the example in the section titled Integrating JSF and JPA from Chapter 6 of the book Java EE 5 Development using GlassFish Application Server so that the web application acts as a client to the DAO session bean we saw in the previous section. In order to make this application act as an EJB client, we will modify the CustomerController managed bean so that it delegates the logic to save a new customer to the database to the CustomerDaoBeansession bean we developed in the previous section.

    package net.ensode.glassfishbook.jsfjpa;
import javax.ejb.EJB;
import net.ensode.glassfishbook.Customer;
import net.ensode.glassfishbook.CustomerDao;
public class CustomerController
{
@EJB
CustomerDao customerDao;
private Customer customer;
public String saveCustomer()
{
String returnValue = "success";
try
{
customerDao.saveCustomer(customer);
}
catch (Exception e)
{
e.printStackTrace();
returnValue = "failure";
}
return returnValue;
}
public Customer getCustomer()
{
return customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
}

As you can see, all we had to do was to declare an instance of the CustomerDaobusiness interface, and decorate it with the @EJB annotation so that an instance of the corresponding EJB is injected, and replace the code to save data to the database with an invocation to the saveCustomer() method, which is defined in the CustomerDaobusiness interface.

Now that we have modified our web application to be a client for our session bean, we need to package it in a WAR file. Then we need to package the WAR file, alongwith the EJB JAR file containing the session bean, in an EAR file.

An EAR file is a compressed ZIP file containing WAR files, EJB JAR files, and any additional libraries that either the web application or the EJB might depend on. An EAR file also contains an application.xml deployment descriptor. This deployment descriptor must be placed in a META-INF directory inside the EAR file.

The structure of our EAR file is shown in the following screenshot.

Enterprise JavaBeans

The application.xml deployment descriptor declares all the Java EE modules that are included in the EAR file.

    <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC
"-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN"
"http://java.sun.com/dtd/application_1_3.dtd">
<application>
<display-name>savecustomer_ear</display-name>
<module>
<web>
<web-uri>daosessionbeanwebclient.war</web-uri>
<context-root>/daosessionbeanwebclient</context-root>
</web>
</module>
<module>
<ejb>daosessionbean.jar</ejb>
</module>
</application>

Each module must be nested inside a <module> element, followed by either an <ejb> element for EJB modules, a <web> element for web modules, or a <java> element for EJB clients that are not web applications.

<ejb> and <java> elements specify the name of the JAR file to be deployed. <web> elements contain a required <web-uri> element indicating the name of the WAR file to be deployed, and an optional <context-root> element used to specify the context root of the web application. If no <context-root> element is present, then the basename of the WAR file is used as its context root.

An EAR file can be created by using a ZIP tool (WinZip, 7-Zip, etc.) to create a ZIPfile with its contents, or, more likely, an IDE or build tool such as Eclipse, NetBeans, ANT or Maven can be used to automate its creation. An EAR file must end with a .ear extension. Once the EAR file is created, the easiest way to deploy it is to copy it into the autodeploy directory under [glassfish installation directory]/glassfish/domains/domain1.

Message-Driven Beans

The purpose of a message-driven bean is to consume messages from a JMS Queueor a JMS topic, depending on the messaging domain used. A message-driven bean must be decorated with the @MessageDriven annotation. The mappedName attribute of this annotation must contain the JNDI name of the JMS message queue or JMS message topic from which the bean will be consuming messages. The following example illustrates a simple message-driven bean:

    package net.ensode.glassfishbook;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
@MessageDriven(mappedName = "jms/GlassFishBookQueue")
public class ExampleMessageDrivenBean implements MessageListener
{
public void onMessage(Message message)
{
TextMessage textMessage = (TextMessage) message;
try
{
System.out.print("Received the following message: ");
System.out.println(textMessage.getText());
System.out.println();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}

It is recommended, but not required for message-driven beans to implement the javax.jms.MessageListener interface, however; message-driven beans must have a method called onMessage() whose signature is identical to this example.

Client applications never invoke a message-driven bean's methods directly, instead they put messages in the message queue or topic, then the bean consumes those messages and acts as appropriate. The preceding example simply prints the message to standard output; as message-driven beans execute inside an EJB container, standard output gets redirected to a log. To see the messages in GlassFish's serverlog, open the [GlassFish installation directory]/glassfish/domains/domain1/logs/server.log file

Summary

In  this article, we learnt about the Enterprise JavaBeans, and their different types. We saw a simple example of a session bean followed by a more realistic one. Then we saw how to use a Session Bean to implement the DAO design pattern. And finally we covered Message-Driven Beans with the help of a simple example

Java EE 5 Development using GlassFish Application Server The complete guide to installing and configuring the GlassFish Application Server and developing Java EE 5 applications to be deployed to this server
Published: October 2007
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


David R. Heffelfinger

David Heffelfinger is the Chief Technology Officer of Ensode Technology, LLC, a software consulting firm based in the greater Washington DC area. He has been architecting, designing and developing software professionally since 1995 and has been using Java as his primary programming language since 1996. He has worked on many large scale projects for several clients including the US Department of Homeland Security, Freddie Mac, Fannie Mae, and the US Department of Defense. He has a Masters degree in Software Engineering from Southern Methodist University. David is editor in chief of Ensode.net (http://www.ensode.net), a website about Java, Linux, and other technology topics.

Books From Packt

Spring Web Flow 2 Web Development
Spring Web Flow 2 Web Development

Learning Ext JS
Learning Ext JS

JDBC 4.0 and Oracle JDeveloper for J2EE Development
JDBC 4.0 and Oracle JDeveloper for J2EE Development

JBoss Drools Business Rules
JBoss Drools Business Rules

Service Oriented Architecture with Java
Service Oriented Architecture with Java

JBoss Tools 3 Developers Guide
Tools 3 Developers Guide

Java EE 5 Development with NetBeans 6
Java EE 5 Development with NetBeans 6

Service Oriented Java Business Integration
Service Oriented Java Business Integration

 

 

 

 

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
n
X
M
T
m
U
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software