Creating a JEE Application with EJB

Ram Kulkarni

September 2015

 In this article by Ram Kulkarni, author of Java EE Development with Eclipse (e2), we will be using EJBs (Enterprise Java Beans) to implement business logic. This is ideal in scenarios where you want components that process business logic to be distributed across different servers. But that is just one of the advantages of EJB. Even if you use EJBs on the same server as the web application, you may gain from a number of services that the EJB container provides to the applications through EJBs. You can specify security constraints for calling EJB methods declaratively (using annotations), and you can also easily specify transaction boundaries (specify which method calls from a part of one transaction) using annotations. In addition to this, the container handles the life cycle of EJBs, including pooling of certain types of EJB objects so that more objects can be created when the load on the application increases.

(For more resources related to this topic, see here.)

In this article, we will create the same application using EJBs and deploy it in a Glassfish 4 server. But before that, you need to understand some basic concepts of EJBs.

Types of EJB

EJBs can be of following types as per the EJB 3 specifications:

  1. Session bean:
  2. Stateful session bean
  3. Stateless session bean
  4. Singleton session bean
  5. Message-driven bean

In this article, we will focus on session beans.

Session beans

In general, session beans are meant for containing methods used to execute the main business logic of enterprise applications. Any Plain Old Java Object (POJO) can be annotated with the appropriate EJB-3-specific annotations to make it a session bean. Session beans come in three types, as follows.

Stateful session bean

One stateful session bean serves requests for one client only. There is a one-to-one mapping between the stateful session bean and the client. Therefore, stateful beans can hold state data for the client between multiple method calls. In our CourseManagement application, we can use a stateful bean to hold the Student data (student profile and the courses taken by him/her) after a student logs-in. The state maintained by the Stateful bean is lost when the server restarts or when the session times out. Since there is one stateful bean per client, using a stateful bean might impact the scalability of the application.

We use the @Stateful annotation to create a stateful session bean.

Stateless session bean

A stateless session bean does not hold any state information for any client. Therefore, one session bean can be shared across multiple clients. The EJB container maintains pools of stateless beans, and when a client request comes, it takes out a bean from the pool, executes methods, and returns the bean to the pool. Stateless session beans provide excellent scalability because they can be shared and need not be created for each client.

We use the @Stateless annotation to create a stateless session bean.

Singleton session bean

As the name suggests, there is only one instance of a singleton bean class in the EJB container (this is true in the clustered environment too; each EJB container will have an instance of a singleton bean). This means that they are shared by multiple clients, and they are not pooled by EJB containers (because there can be only one instance). Since a singleton session bean is a shared resource, we need to manage concurrency in it. Java EE provides two concurrency management options for singleton session beans: container-managed concurrency and bean-managed concurrency. Container-managed concurrency can easily be specified by annotations. See https://docs.oracle.com/javaee/7/tutorial/ejb-basicexamples002.htm#GIPSZ for more information on managing concurrency in a singleton session bean. Using a singleton bean could have an impact on the scalability of the application if there are resource contentions in the code.

We use the @Singleton annotation to create a singleton session bean

Accessing a session bean from the client

Session beans can be designed to be accessed locally (within the same application as a session bean) or remotely (from a client running in a different application or JVM) or both. In the case of remote access, session beans are required to implement a remote interface. For local access, session beans can implement a local interface or no interface (the no-interface view of a session bean). Remote and local interfaces that session beans implement are sometimes also called business interfaces, because they typically expose the primary business functionality.

Creating a no-interface session bean

To create a session bean with a no-interface view, create a POJO and annotate it with the appropriate EJB annotation type and @LocalBean. For example, we can create a local stateful Student bean as follows:

import javax.ejb.LocalBean;
import javax.ejb.Singleton;

@Singleton
@LocalBean
public class Student {
...
}

Accessing a session bean using dependency injection

You can access session beans by either using the @EJBannotation (for dependency injection) or performing a Java Naming and Directory Interface (JNDI) lookup. EJB containers are required to make the JNDI URLs of EJBs available to clients.

Dependency injection of session beans using @EJB work only for managed components, that is, components of the application whose life cycle is managed by the EJB container. When a component is managed by the container, it is created (instantiated) by the container and also destroyed by the container. You do not create managed components using the new operator. JEE-managed components that support direct injection of EJBs are servlets, managed beans of JSF pages and EJBs themselves (one EJB can have other EJBs injected into it). Unfortunately, you cannot have a web container injecting EJBs into JSPs or JSP beans. Also, you cannot have EJBs injected into any custom classes that you create and are instantiated using the new operator.

We can use the Student bean (created previously) from a managed bean of JSF, as follows:

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class StudentJSFBean {
@EJB
private Student studentEJB;
}

Note that if you create an EJB with a no-interface view, then all the public methods in that EJB will be exposed to the clients. If you want to control which methods can be called by clients, then you should implement the business interface.

Creating a session bean using a local business interface

A business interface for EJB is a simple Java interface with either the @Remote or @Local annotation. So we can create a local interface for the Student bean as follows:

import java.util.List;
import javax.ejb.Local;

@Local
public interface StudentLocal {
public List<Course> getCourses();
}

We implement a session bean like this:

import java.util.List;
import javax.ejb.Local;
import javax.ejb.Stateful;

@Stateful
@Local
public class Student implements StudentLocal {
@Override
public List<CourseDTO> getCourses() {
   //get courses are return
…
}
}

Clients can access the Student EJB only through the local interface:

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;

@ManagedBean
public class StudentJSFBean {
@EJB
private StudentLocal student;
}

The session bean can implement multiple business interfaces.

Accessing a session bean using a JNDI lookup

Though accessing EJB using dependency injection is the easiest way, it works only if the container manages the class that accesses the EJB. If you want to access EJB from a POJO that is not a managed bean, then dependency injection will not work. Another scenario where dependency injection does not work is when EJB is deployed in a separate JVM (this could be on a remote server). In such cases, you will have to access EJB using a JNDI lookup (visit https://docs.oracle.com/javase/tutorial/jndi/ for more information on JNDI).

JEE applications can be packaged in an Enterprise Application Archive (EAR), which contains a .jar file for EJBs and a WAR file for web applications (and the lib folder contains the libraries required for both). If, for example, the name of an EAR file is CourseManagement.ear and the name of an EJB JAR file in it is CourseManagementEJBs.jar, then the name of the application is CourseManagement (the name of the EAR file) and the module name is CourseManagementEJBs. The EJB container uses these names to create a JNDI URL for lookup EJBs. A global JNDI URL for EJB is created as follows:

"java:global/<application_name>/<module_name>/<bean_name>![<bean_interface>]"
  • java:global: Indicates that it is a global JNDI URL.
  • <application_name>: The application name is typically the name of the EAR file.
  • <module_name>: This is the name of the EJB JAR.
  • <bean_name>: This is the name of the EJB bean class.
  • <bean_interface>: This is optional if EJB has a no-interface view, or if it implements only one business interface. Otherwise, it is a fully qualified name of a business interface.

EJB containers are also required to publish two more variations of JNDI URLs for each EJB. These are not global URLs, which means that they can't be used to access EJBs from clients that are not in the same JEE application (in the same EAR):

"java:app/[<module_name>]/<bean_name>![<bean_interface>]"
"java:module/<bean_name>![<bean_interface>]"

The first URL can be used if the EJB client is in the same application, and the second URL can be used if the client is in the same module (the same JAR file as the EJB).

Before you look up any URL in a JNDI server, you need to create an InitialContext that includes information, among other things such as the hostname of JNDI server and the port on which it is running. If you are creating InitialContext in the same server, then there is no need to specify these attributes:

InitialContext initCtx = new InitialContext();
Object obj = initCtx.lookup("jndi_url");

We can use the following JNDI URLs to access a no-interface (LocalBean) Student EJB (assuming that the name of the EAR file is CourseManagement and the name of the JAR file for EJBs is CourseManagementEJBs):

URL

When to use

java:global/CourseManagement/ CourseManagementEJBs/Student

The client can be anywhere in the EAR file, because we are using a global URL. Note that we haven't specified the interface name because we are assuming that the Student bean provides a no-interface view in this example.

java:app/CourseManagementEJBs/Student

The client can be anywhere in the EAR. We skipped the application name because the client is expected to be in the same application. This is because the namespace of the URL is java:app.

java:module/Student

The client must be in the same JAR file as EJB.

We can use the following JNDI URLs to access the Student EJB that implemented a local interface, StudentLocal:

URL

When to use

java:global/CourseManagement/ CourseManagementEJBs/Student!packt.jee.book.ch6.StudentLocal

The client can be anywhere in the EAR file, because we are using a global URL.

java:global/CourseManagement/ CourseManagementEJBs/Student

The client can be anywhere in the EAR. We skipped the interface name because the bean implements only one business interface. Note that the object returned from this call will be of the StudentLocal type, and not Student.

java:app/CourseManagementEJBs/Student

Or

java:app/CourseManagementEJBs/Student!packt.jee.book.ch6.StudentLocal

The client can be anywhere in the EAR. We skipped the application name because the JNDI namespace is java:app.

java:module/Student

Or

java:module/Student!packt.jee.book.ch6.StudentLocal

The client must be in the same EAR as the EJB.

Here is an example of how we can call the Student bean with the local business interface from one of the objects (that is not managed by the web container) in our web application:

InitialContext ctx = new InitialContext();
StudentLocal student = (StudentLocal) ctx.loopup ("java:app/CourseManagementEJBs/Student");
return student.getCourses(id) ; //get courses from Student EJB

Creating EAR for Deployment outside Eclipse.

Summary

EJBs are ideal for writing business logic in web applications. They can act as the perfect bridge between web interface components, such as a JSF, servlet, or JSP, and data access objects, such as JDO. EJBs can be distributed across multiple JEE application servers (this could improve application scalability) and their life cycle is managed by the container. EJBs can easily be injected into managed objects or can be looked up using JNDI.

The Eclipse JEE makes creating and consuming EJBs very easy. The JEE application server Glassfish can also be managed and applications can be deployed from within Eclipse.

Resources for Article:


Further resources on this subject:


You've been reading an excerpt of:

Java EE Development with Eclipse - Second Edition

Explore Title