CHAPTER 7

image

Enterprise JavaBeans

The previous chapter showed how to implement persistent objects using JPA and how to query them with JPQL. Entities can have methods to validate their attributes, but they are not made to represent complex tasks, which often require an interaction with other components (other persistent objects, external services, etc.). The persistence layer is not the appropriate layer for business processing. Similarly, the user interface should not perform business logic, especially when there are multiple interfaces (Web, Swing, portable devices, etc.). To separate the persistence layer from the presentation layer, to implement business logic, to add transaction management and security, applications need a business layer. In Java EE, we implement this layer using Enterprise JavaBeans (EJBs).

For most applications, layering is important. Following a bottom-up approach, the previous chapters on JPA modeled domain classes, usually defining nouns (Artist, CD, Book, Customer, etc.). On top of the domain layer, the business layer models the actions (or verbs) of the application (create a book, buy a book, print an order, deliver a book, etc.). Often, this business layer interacts with external web services (SOAP or RESTful web services), sends asynchronous messages to other systems (using JMS), or posts e-mails; it orchestrates several components from databases to external systems, and serves as the central place for transaction and security demarcation as well as the entry point to any kind of client such as web interfaces (Servlets or JSF backing beans), batch processing, or external systems. This logical separation between entities and session beans follows the “separation of concerns” paradigm wherein an application is split into separate components whose functions overlap as little as possible.

This chapter introduces you to EJBs and then explains the three different types of session beans: stateless, stateful, and singleton Stateless beans are the most scalable of the three, as they keep no state and complete business logic in a single method call. Stateful beans maintain a conversational state with one client. EJB 3.1 brought the singleton session bean (one instance per application) into the previous release. You will also see how to execute these EJBs in an embedded container and invoke them synchronously or asynchronously.

Understanding Enterprise JavaBeans

EJBs are server-side components that encapsulate business logic and take care of transactions and security. They also have an integrated stack for messaging, scheduling, remote access, web service endpoints (SOAP and REST), dependency injection, component life cycle, AOP (aspect-oriented programming) with interceptors, and so on. In addition, EJBs seamlessly integrate with other Java SE and Java EE technologies, such as JDBC, JavaMail, JPA, Java Transaction API (JTA), Java Messaging Service (JMS), Java Authentication and Authorization Service (JAAS), Java Naming and Directory Interface (JNDI), and Remote Method Invocation (RMI). This is why they are used to build the business logic layer (see Figure 7-1), sit on top of the database, and orchestrate the business model layer. EJBs act as an entry point for presentation-tier technologies like JavaServer Faces (JSF) but also for all external services (JMS or web services).

9781430246268_Fig07-01.jpg

Figure 7-1. Architecture layering

EJBs use a very powerful programming model that combines ease of use and robustness. Today EJBs are a very simple Java server-side development model, reducing complexity while bringing reusability and scalability to mission-critical enterprise applications. All this comes from annotating a single POJO that will be deployed into a container. An EJB container is a runtime environment that provides services, such as transaction management, concurrency control, pooling, and security authorization. Historically, application servers have added other features such as clustering, load balancing, and failover. EJB developers can then concentrate on implementing business logic while the container deals with all the technical plumbing.

Today more than ever, with version 3.2, EJBs can be written once and deployed on any container that supports the specification. Standard APIs, portable JNDI names, lightweight components, CDI integration, and configuration by exception allow easy deployment of EJBs on open source as well as commercial implementations. The underlying technology was created more than 12 years ago, resulting in EJB applications that benefit from proven concepts.

Types of EJBs

Session beans are great for implementing business logic, processes, and workflow. And because enterprise applications can be complex, the Java EE platform defines several types of EJBs. A session bean may have the following traits:

  • Stateless: The session bean contains no conversational state between methods, and any instance can be used for any client. It is used to handle tasks that can be concluded with a single method call.
  • Stateful: The session bean contains conversational state, which must be retained across methods for a single user. It is useful for tasks that have to be done in several steps.
  • Singleton: A single session bean is shared between clients and supports concurrent access. The container will make sure that only one instance exists for the entire application.

The three types of session beans all have their specific features, of course, but they also have a lot in common. First of all, they have the same programming model. As you’ll see later on, a session bean can have a local and/or remote interface, or no interface at all. Session beans are container-managed components, so they need to be packaged in an archive (jar, war, or ear file) and deployed to a container.

Message-driven beans (MDBs) are used for integrating with external systems by receiving asynchronous messages using JMS. Even though MDBs are part of the EJB specification, I deal with them separately (in Chapter 13) because this component model is mainly used to integrate systems with message-oriented middleware (MOM). MDBs usually delegate the business logic to session beans.

EJBs can also be used as web service endpoints. Chapters 14 and 15 demonstrate SOAP and RESTful web services that can be either simple POJOs deployed in a web container or session beans deployed in an EJB container.

image Note  For compatibility reasons, the EJB 3.1 specification still included Entity CMP. This persistent component model has been pruned and is now optional in EJB 3.2. JPA is the preferred technology for mapping and querying relational databases. This book does not cover Entity CMP.

Process and Embedded Container

Right from the moment they were invented (EJB 1.0), EJBs had to be executed in a container that would run on top of a JVM. Think of GlassFish, JBoss, Weblogic, and so on, and you’ll remember that the application server first needs to be started before deploying and using your EJB. This in-process container is appropriate for a production environment, where the server runs continuously. But it is time-consuming in a development environment where you frequently need to start, deploy, debug, and stop the container. Another issue with servers running in a different process is that testing capabilities are limited. Either you mock all the container services for unit testing or you need to deploy your EJB in a live server to perform integration tests. To solve these problems, some application server implementations came with embedded containers, but these were implementation specific. Since EJB 3.1 the expert group has standardized an embedded container that is portable across servers.

The idea of an embedded container is to be able to execute EJB applications within a Java SE environment allowing clients to run within the same JVM and class loader. This provides better support for integration testing, offline processing (e.g., batch processing), and the use of the EJB in desktop applications. The embeddable container API provides the same managed environment as the Java EE runtime container and includes the same services. You can now execute the embedded container on the same JVM as your IDE and debug your EJB without doing any deployment to a separate application server.

Services Given by the Container

No matter if the container is embedded or runs in a separate process, it provides core services common to many enterprise applications such as the following:

  • Remote client communication: Without writing any complex code, an EJB client (another EJB, a user interface, a batch process, etc.) can invoke methods remotely via standard protocols.
  • Dependency injection: The container can inject several resources into an EJB (JMS destinations and factories, datasources, other EJBs, environment variables, etc.) as well as any POJO thanks to CDI.
  • State management: For stateful session beans, the container manages their state transparently. You can maintain state for a particular client, as if you were developing a desktop application.
  • Pooling: For stateless beans and MDBs, the container creates a pool of instances that can be shared by multiple clients. Once invoked, an EJB returns to the pool to be reused instead of being destroyed.
  • Component life cycle: The container is responsible for managing the life cycle of each component.
  • Messaging: The container allows MDBs to listen to destinations and consume messages without too much JMS plumbing.
  • Transaction management: With declarative transaction management, an EJB can use annotations to inform the container about the transaction policy it should use. The container takes care of the commit or the rollback.
  • Security: Class or method-level access control can be specified on EJBs to enforce user and role authorization.
  • Concurrency support: Except for singletons, where some concurrency declaration is needed, all the other types of EJB are thread-safe by nature. You can develop high-performance applications without worrying about thread issues.
  • Interceptors: Cross-cutting concerns can be put into interceptors, which will be invoked automatically by the container.
  • Asynchronous method invocation: Since EJB 3.1, it’s now possible to have asynchronous calls without involving messaging.

Once the EJB is deployed, the container takes care of these features, leaving the developer to focus on business logic while benefiting from these services without adding any system-level code.

EJBs are managed objects. In fact they are considered to be Managed Beans. When a client invokes an EJB, it doesn’t work directly with an instance of that EJB but rather with a proxy on an instance. Each time a client invokes a method on an EJB, the call is actually proxied and intercepted by the container, which provides services on behalf of the bean instance. Of course, this is completely transparent to the client; from its creation to its destruction, an enterprise bean lives in a container.

In a Java EE application, the EJB container will usually interact with other containers: the Servlet container (responsible for managing the execution of Servlets and JSF pages), the application client container (ACC) (for managing stand-alone applications), the message broker (for sending, queuing, and receiving messages), the persistence provider, and so on.

Containers give EJBs a set of service. On the other hand, EJBs cannot create or manage threads, access files using java.io, create a ServerSocket, load a native library, or use the AWT (Abstract Window Toolkit)or Swing APIs to interact with the user.

EJB Lite

Enterprise Java Beans are the predominant component model in Java EE 7, being the simplest method for transactional and secure business processing. However, EJB 3.2 still defines complex technologies that are less used today such as IIOP (Internet InterOrb Protocol) interoperability, meaning that any new vendor implementing the EJB 3.2 specification has to implement it. Developers getting started with EJBs would also be weighed down by many technologies that they would never use otherwise.

For these reasons, the specification defines a minimal subset of the full EJB API known as EJB Lite. It includes a small, powerful selection of EJB features suitable for writing portable transactional and secure business logic. Any EJB Lite application can be deployed on any Java EE product that implementsEJB 3.2. EJB Lite is composed of the subset of the EJB API listed in Table 7-1.

Table 7-1. Comparison Between EJB Lite and Full EJB

Feature EJB Lite Full EJB 3.2
Session beans (stateless, stateful, singleton) Yes Yes
No-interface view Yes Yes
Local interface Yes Yes
Interceptors Yes Yes
Transaction support Yes Yes
Security Yes Yes
Embeddable API Yes Yes
Asynchronous calls No Yes
MDBs No Yes
Remote interface No Yes
JAX-WS web services No Yes
JAX-RS web services No Yes
Timer service No Yes
RMI/IIOP interoperability No Yes

image Note  Since the beginning the EJB specifications required the capability of using RMI/IIOP to export EJB components and to access EJB components over a network. This requirement allowed interoperability between Java EE products. This requirement has been pruned in EJB 3.2 and might become optional in future releases, because RMI/IIOP has been largely superseded by modern web technologies that provide interoperability support, such as SOAP and REST.

EJB Specification Overview

EJB 1.0 was created back in 1998, and EJB 3.2 was released in 2013 with Java EE 7. During these 15 years, the EJB specification went through many changes, but it still retains its mature foundations. From heavyweight components to annotated POJOs, from Entity Bean CMP to JPA, EJBs have reinvented themselves to meet the needs of developers and modern architectures.

More than ever, the EJB 3.2 specification helps to avoid vendor lock-in by providing features that were previously nonstandard (such as nonstandard JNDI names or embedded containers). Today, EJB 3.2 is much more portable than in the past.

A Brief History of the EJB Specification

Soon after the creation of the Java language, the industry felt the need for a technology that could address the requirements of large-scale applications, embracing RMI and JTA. The idea of creating a distributed and transactional business component framework arose, and as a result IBM first started creating what eventually became known as EJBs.

EJB 1.0 supported stateful and stateless session beans, with optional support for entity beans. The programming model used home and remote interfaces in addition to the session bean itself. EJBs were made accessible through an interface that offered remote access with arguments passed by value.

EJB 1.1 mandated support for entity beans and introduced the XML deployment descriptor to store metadata (which was then serialized as binary in a file). This version provided better support for application assembly and deployment by introducing roles.

In 2001, EJB 2.0 was the first version to be standardized by the Java Community Process (as JSR 19). It addressed the overhead of passing arguments by value by introducing local interfaces. Clients running inside the container would access EJBs through their local interface (using arguments passed by reference), and clients running in a different container would use the remote interface. This version introduced MDBs, and entity beans gained support for relationships and a query language (EJB QL).

Two years later, EJB 2.1 (JSR 153) added support for web services, allowing session beans to be invoked through SOAP/HTTP. A timer service was created to allow EJBs to be invoked at designated times or intervals.

Three years passed between EJB 2.1 and EJB 3.0, which allowed the expert group to remodel the entire design. In 2006, the EJB 3.0 specification (JSR 220) broke with previous versions as it focused on ease of use, with EJBs looking more like POJOs. The entity beans were replaced by a brand-new specification (JPA), and session beans no longer required home or EJB-specific component interfaces. Resource injection, interceptors, and life-cycle callbacks were introduced.

In 2009, the EJB 3.1 specification (JSR 318) shipped with Java EE 6, following the path of the previous version by simplifying the programming model even further. The 3.1 version brought an amazing number of new features such as the no-interface view, embedded container, singleton, a richer timer service, asynchrony, portable JNDI, and EJB Lite.

What’s New in EJB 3.2?

The EJB 3.2 specification (JSR 345) is less ambitious than the previous release. To simplify future adoption of the specification, the Java EE 6 expert group had compiled a list of features for possible future removal (a.k.a. pruning). None of the following features were actually removed from EJB 3.1, but they all became optional in 3.2.

  • Entity bean 2.x
  • Client view of an entity bean 2.x
  • EJB QL (query language for CMP)
  • JAX-RPC–based web service endpoints
  • Client view of a JAX-RPC web service

That’s why the specification itself is organized into two different documents.

  • “EJB Core Contracts and Requirements:” The main document that specifies EJBs.
  • “EJB Optional Features:” The document that describes the previously listed features for which support has been made optional.

The EJB 3.2 specification includes the following minor updates and improvements:

  • Transactions can now be used by Managed Beans (previously only EJBs could use transactions; more in Chapter 9).
  • Stateful session bean life-cycle callback methods can opt-in to be transactional.
  • Passivation for stateful session bean is now opted out.
  • The rules to define all local/remote views of the bean have been simplified.
  • Restriction to obtain the current class loader has been removed, and the use of the java.io package is now allowed.
  • Allignment of JMS 2.0.
  • Embeddable container implements Autocloseable to fit Java SE 7.
  • RMI/IIOP has been pruned in this release. This means that it might be marked as optional in Java EE 8. Remote invocation would then be done with just RMI (without the IIOP interoperability).

Table 7-2 lists the main packages defined in EJB 3.2 today.

Table 7-2. Main EJB Packages

Package Description
javax.ejb Classes and interfaces that define the contracts between the EJB and its clients and between the EJB and the container
javax.ejb.embeddable Classes for the embeddable API
javax.ejb.spi Interfaces that are implemented by the EJB container

Reference Implementation

GlassFish is an open source application server project led by Oracle for the Java EE platform. Sun launched the project in 2005 and it became the reference implementation of Java EE 5 in 2006. Today, GlassFish v4 includes the reference implementation for EJB 3.2. Internally, the product is built around modularity (based on the Apache Felix OSGi runtime), allowing a very fast startup time and the use of various application containers (Java EE 7, of course, but also Ruby, PHP, etc.).

At the time of writing this book GlassFish is the only EJB 3.2 compliant implementation. But others will soon follow: OpenEJB, JBoss, Weblogic, Websphere . . .

Writing Enterprise Java Beans

Session beans encapsulate business logic, are transactional, and rely on a container that does pooling, multithreading, security, and so on. What artifacts do we need to create such a powerful component? One Java class and one annotationthat’s all. Listing 7-1 shows how simple it is for a container to recognize that a class is a session bean and apply all the enterprise services.

Listing 7-1.  A Simple Stateless EJB

@Stateless
public class BookEJB {
 
  @PersistenceContext(unitName = "chapter07PU")
  private EntityManager em;
 
  public Book findBookById(Long id) {
    return em.find(Book.class, id);
  }
 
  public Book createBook(Book book) {
    em.persist(book);
    return book;
  }
}

Previous versions of J2EE required developers to create several artifacts in order to create a session bean: a local or remote interface (or both), a local home or a remote home interface (or both), and a deployment descriptor. Java EE 5 and EJB 3.0 drastically simplified the model to the point where only one class and one or more business interfaces are sufficient and you don’t need any XML configuration. As shown in Listing 7-1, since EJB 3.1 the class doesn’t even have to implement any interface. We use only one annotation to turn a Java class into a transactional and secure component: @Stateless. Then, using the entity manager (as seen in the previous chapters), the BookEJB creates and retrieves books from the database in a simple yet powerful manner.

Anatomy of an EJB

Listing 7-1 shows the easiest programming model for session beans: an annotated POJO with no interface. But, depending on your needs, session beans can give you a much richer model, allowing you to perform remote calls, dependency injection, or asynchronous calls. An EJB is made of the following elements:

  • A bean class: The bean class contains the business method implementation and can implement zero or several business interfaces. The session bean must be annotated with @Stateless, @Stateful, or @Singleton depending on its type.
  • Business interfaces: These interfaces contain the declaration of business methods that are visible to the client and implemented by the bean class. A session bean can have local interfaces, remote interfaces, or no interface at all (a no-interface view with local access only).

As shown in Figure 7-2, a client application can access a session bean by one of its interfaces (local or remote) or directly by invoking the bean class itself.

9781430246268_Fig07-02.jpg

Figure 7-2. Bean class has several types of business interfaces

Bean Class

A session bean class is any standard Java class that implements business logic. The requirements to develop a session bean class are as follows:

  • The class must be annotated with @Stateless, @Stateful, @Singleton, or the XML equivalent in a deployment descriptor.
  • It must implement the methods of its interfaces, if any.
  • The class must be defined as public, and must not be final or abstract.
  • The class must have a public no-arg constructor that the container will use to create instances.
  • The class must not define the finalize() method.
  • Business method names must not start with ejb, and they cannot be final or static.
  • The argument and return value of a remote method must be legal RMI types.

Remote, Local, and No-Interface Views

Depending from where a client invokes a session bean, the bean class will have to implement remote or local interfaces, or no interface at all. If your architecture has clients residing outside the EJB container’s JVM instance, they must use a remote interface. As shown in Figure 7-3, this applies for clients running in a separate JVM (e.g., a rich client), in an application client container (ACC), or in an external web or EJB container. In this case, clients will have to invoke session bean methods through Remote Method Invocation (RMI). You can use local invocation when the bean and the client are running in the same JVM. That can be an EJB invoking another EJB or a web component (Servlet, JSF) running in a web container in the same JVM. It is also possible for your application to use both remote and local calls on the same session bean.

9781430246268_Fig07-03.jpg

Figure 7-3. Session beans invoked by several types of client

A session bean can implement several interfaces or none. A business interface is a standard Java interface that does not extend any EJB-specific interfaces. Like any Java interface, business interfaces define a list of methods that will be available for the client application. They can use the following annotations:

  • @Remote: Denotes a remote business interface. Method parameters are passed by value and need to be serializable as part of the RMI protocol.
  • @Local: Denotes a local business interface. Method parameters are passed by reference from the client to the bean.

You cannot mark the same interface with more than one annotation. The session beans that you have seen so far in this chapter have no interface. The no-interface view is a variation of the local view that exposes all public business methods of the bean class locally without the use of a separate business interface.

Listing 7-2 shows a local interface (ItemLocal) and a remote interface (ItemRemote) implemented by the ItemEJB stateless session bean. With this code, clients will be able to invoke the findCDs() method locally or remotely as it is defined in both interfaces. The createCd() will only be accessible remotely through RMI.

Listing 7-2.  Stateless Session Bean Implementing a Remote and Local Interface

@Local
public interface ItemLocal {
  List<Book> findBooks();
  List<CD> findCDs ();
}
 
@Remote
public interface ItemRemote {
  List<Book> findBooks();
  List<CD> findCDs ();
  Book createBook(Book book);
  CD createCD (CD cd);
}
 
@Stateless
public class ItemEJB implements ItemLocal , ItemRemote {
  // ...
}

Alternatively to the code in Listing 7-2, you might specify the interface in the bean’s class. In this case, you would have to include the name of the interface in the @Local and @Remote annotations as shown in Listing 7-3. This is handy when you have legacy interfaces where you can’t add annotations and need to use them in your session bean.

Listing 7-3.  A Bean Class Defining a Remote, Local and No Interface

public interface ItemLocal {
  List<Book> findBooks();
  List<CD> findCDs();
}
 
public interface ItemRemote {
  List<Book> findBooks();
  List<CD> findCDs();
  Book createBook(Book book);
  CD createCD(CD cd);
}
 
@Stateless
@Remote(ItemRemote.class)
@Local(ItemLocal.class)
@LocalBean
public class ItemEJB implements ItemLocal , ItemRemote {
  // ...
}

If the bean exposes at least one interface (local or remote) it automatically loses the no-interface view. It then needs to explicitly specify that it exposes a no-interface view by using the @LocalBean annotation on the bean class. As you can see in Listing 7-3 the ItemEJB now has a local, remote, and no interface.

Web Services Interface

In addition to remote invocation through RMI, stateless beans can also be invoked remotely as SOAP web services or RESTful web services. Chapters 14 and 15 are dedicated to web services, so I won’t describe them here. I just want to show you how a stateless session bean can be accessed in various forms just by implementing different annotated interfaces. Listing 7-4 shows a stateless bean with a local interface, a SOAP web services endpoint (@WebService), and a RESTful web service endpoint (@Path). Note that these annotations come, respectively, from JAX-WS (Chapter 14) and JAX-RS (Chapter 15) and are not part of EJB.

Listing 7-4.  A Stateless Session Bean Implementing Several Interfaces

@Local
public interface ItemLocal {
  List<Book> findBooks();
  List<CD> findCDs();
}
 
@WebService
public interface ItemSOAP {
  List<Book> findBooks();
  List<CD> findCDs();
  Book createBook(Book book);
  CD createCD(CD cd);
}
 
@Path(/items)
public interface ItemRest {
    List<Book> findBooks();
}
 
@Stateless
public class ItemEJB implements ItemLocal , ItemSOAP , ItemRest {
  // ...
}

Portable JNDI Name

JNDI has been around for a long time. Its API is specified and is portable across application servers. But this wasn’t the case with the JNDI name, which was implementation specific. When an EJB in GlassFish or JBoss was deployed, the name of the EJB in the directory service was different and thus not portable. A client would have to look up an EJB using one name for GlassFish, and another name for JBoss. Since EJB 3.1, JNDI names have been specified so the code could be portable. So now each time a session bean with its interfaces is deployed to the container, each bean/interface is automatically bound to a portable JNDI name. The Java EE specification defines portable JNDI names with the following syntax:

java:<scope>[/<app-name>]/<module-name>/<bean-name>[!<fully-qualified-interface-name>]

Each portion of the JNDI name has the following meaning:

  • <scope> defines a series of standard namespaces that map to the various scopes of a Java EE application:
  • global: The java:global prefix allows a component executing outside a Java EE application to access a global namespace.
  • app: The java:app prefix allows a component executing within a Java EE application to access an application-specific namespace.
  • module: The java:module prefix allows a component executing within a Java EE application to access a module-specific namespace.
  • comp: The java:comp prefix is a private component-specific namespace and is not accessible by other components.
  • <app-name> is only required if the session bean is packaged within an ear or war file. If this is the case, the <app-name> defaults to the name of the ear or war file (without the .ear or .war file extension).
  • <module-name> is the name of the module in which the session bean is packaged. It can be an EJB module in a stand-alone jar file or a web module in a war file. The <module-name> defaults to the base name of the archive with no file extension.
  • <bean-name> is the name of the session bean.
  • <fully-qualified-interface-name> is the fully qualified name of each defined business interface. For the no-interface view, the name can be the fully qualified bean class name.

To illustrate this naming convention, let’s take the example of an ItemEJB (defined in Listing 7-5), which has a remote interface, a local interface, and a no-interface view (using the @LocalBean annotation). All these classes and interfaces belong to the org.agoncal.book.javaee7 package. ItemEJB is the <bean-name> and is packaged in the cdbookstore.jar (the <module-name>).

Listing 7-5.  A Stateless Session Bean Implementing Several Interfaces

package org.agoncal.book.javaee7 ;
@Stateless
@Remote(ItemRemote.class)
@Local(ItemLocal.class)
@LocalBean
public class ItemEJB implements ItemLocal , ItemRemote {
  // ...
}

Once deployed, the container will create three JNDI names so an external component will be able to access the ItemEJB using the following global JNDI names:

java:global/cdbookstore/ ItemEJB !org.agoncal.book.javaee7. ItemRemote
java:global/cdbookstore/ ItemEJB !org.agoncal.book.javaee7. ItemLocal
java:global/cdbookstore/ ItemEJB !org.agoncal.book.javaee7. ItemEJB

Note that, if the ItemEJB was deployed within an ear file (e.g., myapplication.ear), you would have to use the <app-name> as follow:

java:global/ myapplication /cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemRemote
java:global/ myapplication /cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemLocal
java:global/ myapplication /cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemEJB

The container is also required to make JNDI names available through the java:app and java:module namespaces. So a component deployed in the same application as the ItemEJB will be able to look it up using the following JNDI names:

java: app /cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemRemote
java:app/cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemLocal
java:app/cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemEJB
java: module /ItemEJB!org.agoncal.book.javaee7.ItemRemote
java:module/ItemEJB!org.agoncal.book.javaee7.ItemLocal
java:module/ItemEJB!org.agoncal.book.javaee7.ItemEJB

This portable JNDI name can be applied to all session beans: stateless, stateful, and singleton.

Stateless Beans

In Java EE applications, stateless beans are the most popular session bean components. They are simple, powerful, and efficient and respond to the common task of doing stateless business processing. What does stateless mean? It means that a task has to be completed in a single method call.

As an example, we can go back to the roots of object-oriented programming where an object encapsulates its state and behavior. In object modeling, to persist a book to a database, you would do something like this: create an instance of a Book object (using the new keyword), set some values, and call a method so it could persist itself to a database (book.persistToDatabase()). In the following code, you can see that, from the very first line to the last one, the book object is called several times and keeps its state:

Book book = new Book();
book.setTitle("The Hitchhiker's Guide to the Galaxy");
book.setPrice(12.5F);
book.setDescription("Science fiction comedy series created by Douglas Adams.");
book.setIsbn("1-84023-742-2");
book.setNbOfPage(354);
book. persistToDatabase ();

In a service architecture, you would delegate the business logic to an external service. Stateless services are ideal when you need to implement a task that can be concluded with a single method call (passing all the needed parameters). Stateless services are independent, are self-contained, and do not require information or state from one request to another. So, if you take the preceding code and introduce a stateless service, you need to create a Book object, set some values, and then use a stateless service to invoke a method that will persist the book on its behalf, in a single call. The state is maintained by Book but not by the stateless service:

Book book = new Book();
book.setTitle("The Hitchhiker's Guide to the Galaxy");
book.setPrice(12.5F);
book.setDescription("Science fiction comedy series created by Douglas Adams.");
book.setIsbn("1-84023-742-2");
book.setNbOfPage(354);
statelessService .persistToDatabase( book );

Stateless session beans follow the stateless service architecture and are the most efficient component model because they can be pooled and shared by several clients. This means that, for each stateless EJB, the container keeps a certain number of instances in memory (i.e., a pool) and shares them between clients. Because stateless beans have no client state, all instances are equivalent. When a client invokes a method on a stateless bean, the container picks up an instance from the pool and assigns it to the client. When the client request finishes, the instance returns to the pool to be reused. This means you need only a small number of beans to handle several clients, as shown in Figure 7-4. The container doesn’t guarantee the same instance for the same client.

9781430246268_Fig07-04.jpg

Figure 7-4. Clients accessing stateless beans in a pool

Listing 7-5 shows what a stateless EJB could look like: a standard Java class with just a single @Stateless annotation. Because it lives in a container, it can use any container-managed service, one of which is dependency injection. We use the @PersistenceContext annotation to inject a reference of an entity manager. For stateless session beans, the persistence context is transactional, which means that any method invoked in this EJB (createBook(), createCD(), etc.) is transactional. Chapter 9 explains this process in more detail. Notice that all methods have the needed parameters to process business logic in one single call. For example, the createBook() method takes a Book as a parameter and persists it without relying on any other state.

Listing 7-5.  Stateless Session Bean ItemEJB

@Stateless
public class ItemEJB {
 
  @PersistenceContext(unitName = "chapter07PU")
  private EntityManager em ;
 
  public List<Book> findBooks() {
    TypedQuery<Book> query = em .createNamedQuery(Book.FIND_ALL, Book.class);
    return query.getResultList();
  }
 
  public List<CD> findCDs() {
    TypedQuery<CD> query = em .createNamedQuery(CD.FIND_ALL, CD.class);
    return query.getResultList();
  }
 
  public Book createBook(Book book) {
    em .persist(book);
    return book;
  }
 
  public CD createCD(CD cd) {
    em .persist(cd);
    return cd;
  }
}

Stateless session beans often contain several closely related business methods. For example, the ItemEJB bean in Listing 7-5 defines methods related to items sold by the CD-BookStore application. So you will find methods to create, update, or find books and CDs, as well as other related business logic.

The @Stateless annotation marks the ItemEJB POJO as a stateless session bean, thus turning a simple Java class into a container-aware component. Listing 7-6 describes the specification of the @javax.ejb.Stateless annotation.

Listing 7-6.  @Stateless Annotation API

@Target({TYPE}) @Retention(RUNTIME)
public @interface Stateless {
    String name () default "";
    String mappedName () default "";
    String description () default "";
}

The name parameter specifies the name of the bean and by default is the name of the class (ItemEJB in the example in Listing 7-5). This parameter can be used to look up an EJB with JNDI, for example. The description parameter is a String that can be used to describe the EJB. The mappedName attribute is the global JNDI name assigned by the container. Note that this JNDI name is vendor specific and is therefore not portable. mappedName has no relationship with the portable global JNDI name, which I described earlier.

Stateless session beans can support a large number of clients, minimizing any needed resources. Having stateless applications is one way to improve scalability (as the container doesn’t have to store and manage state).

Stateful Beans

Stateless beans provide business methods to their clients but don’t maintain a conversational state with them. Stateful session beans, on the other hand, preserve conversational state. They are useful for tasks that have to be done in several steps, each of which relies on the state maintained in a previous step. Let’s take the example of a shopping cart in an e-commerce web site. A customer logs on (her session starts), chooses a first book, adds it to her shopping cart, chooses a second book, and adds it to her cart. At the end, the customer checks out the books, pays for them, and logs out (the session ends). The shopping cart keeps the state of how many books the customer has chosen throughout the interaction (which can take some time, specifically the time of the client’s session). This interaction with a stateful component could be written as follows:

Book book = new Book();
book.setTitle("The Hitchhiker's Guide to the Galaxy");
book.setPrice(12.5F);
book.setDescription("Science fiction comedy series created by Douglas Adams.");
book.setIsbn("1-84023-742-2");
book.setNbOfPage(354);
statefulComponent .addBookToShoppingCart( book );
book.setTitle("The Robots of Dawn");
book.setPrice(18.25F);
book.setDescription("Isaac Asimov's Robot Series");
book.setIsbn("0-553-29949-2");
book.setNbOfPage(276);
statefulComponent .addBookToShoppingCart( book );
statefulComponent .checkOutShoppingCart();

The preceding code shows exactly how a stateful session bean works. Two books are created and added to a shopping cart of a stateful component. At the end, the checkOutShoppingCart() method relies on the maintained state and can check out the two books.

When a client invokes a stateful session bean in the server, the EJB container needs to provide the same instance for each subsequent method invocation. Stateful beans cannot be reused by other clients. Figure 7-5 shows the one-to-one correlation between a bean instance and a client. As far as the developer is concerned, no extra code is needed, as the EJB container automatically manages this one-to-one correlation.

9781430246268_Fig07-05.jpg

Figure 7-5. Clients accessing stateful beans

The one-to-one correlation comes at a price because, as you might have guessed, if you have one million clients, you will get one million stateful beans in memory. To avoid such a big memory footprint, the container temporarily clears stateful beans from memory before the next request from the client brings them back. This technique is called passivation and activation. Passivation is the process of removing an instance from memory and saving it to a persistent location (a file on a disk, a database, etc.). It helps you to free memory and release resources (a database or JMS connections, etc.). Activation is the inverse process of restoring the state and applying it to an instance. Passivation and activation are done automatically by the container; you shouldn’t worry about doing it yourself, as it’s a container service. What you should worry about is freeing any resource (e.g., database connection, JMS factories connection, etc.) before the bean is passivated. Since EJB 3.2, you can also disable passivation as you’ll see in the next chapter with life-cycle and callback annotations.

Let’s return to the shopping-cart example and apply it to a stateful bean (see Listing 7-7). A customer logs on to a web site, browses the catalog of items, and adds two books to the shopping cart (addItem() method). The cartItems attribute holds the content of the cart. Then the customer decides to get a coffee at a coffee machine. During this time, the container might passivate the instance to free some memory, which in turn saves the shopping content to permanent storage. A few minutes later, the customer comes back and wants to know the total price (getTotal() method) of his shopping cart before buying anything. The container activates the EJB and restores the data to the shopping cart. The customer can then check out (checkout() method) and buy the books. Once the customer logs off, the customer’s session ends, and the container frees memory by permanently removing the instance of the stateful bean.

Listing 7-7.  Stateful Session Bean ShoppingCartEJB

@Stateful
@StatefulTimeout(value = 20, unit = TimeUnit.SECONDS)
public class ShoppingCartEJB {
 
  private List<Item> cartItems = new ArrayList<>();
 
  public void addItem(Item item) {
    if (!cartItems.contains(item))
      cartItems.add (item);
  }
 
  public void removeItem(Item item) {
    if (cartItems.contains(item))
      cartItems.remove (item);
  }
 
  public Integer getNumberOfItems() {
    if (cartItems == null || cartItems.isEmpty())
      return 0;
    return cartItems.size ();
  }
 
  public Float getTotal() {
    if (cartItems == null || cartItems.isEmpty())
      return 0f;
 
    Float total = 0f;
    for (Item cartItem : cartItems ) {
      total += (cartItem.getPrice());
    }
    return total;
  }
 
  public void empty() {
    cartItems.clear();
  }
 
  @Remove
  public void checkout() {
    // Do some business logic
    cartItems.clear ();
  }
}

The shopping-cart situation is a standard way of using stateful beans in which the container automatically takes care of maintaining the conversational state. The only needed annotation is @javax.ejb.Stateful, which has the same API as @Stateless, described in Listing 7-6.

Notice the optional @javax.ejb.StatefulTimeout and @javax.ejb.Remove annotations. @Remove decorates the checkout() method. This causes the bean instance to be permanently removed from memory after you invoke the checkout() method. @StatefulTimeout assigns a timeout value, which is the duration the bean is permitted to remain idle (not receiving any client invocations) before being removed by the container. The time unit of this annotation is a java.util.concurrent.TimeUnit, so it can go from DAYS, HOURS ... to NANOSECONDS (the default is MINUTES). Alternatively, you can avoid these annotations and rely on the container automatically removing an instance when the client’s session ends or expires. However, making sure the stateful bean is removed at the appropriate moment might reduce memory consumption. This could be critical in highly concurrent applications.

Singletons

A singleton bean is a session bean that is instantiated once per application. It implements the widely used Singleton pattern from the famous book by the Gang of Four: Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John M. Vlissides (Addison-Wesley, 1995). A singleton ensures that only one instance of a class exists in the whole application and provides a global point to access to it. There are many situations that need singleton objectsthat is, where your application only needs one instance of an object: a mouse, a window manager, a printer spooler, a file system, and so on.

Another common-use case is a caching system whereby the entire application shares a single cache (e.g., a Hashmap) to store objects. In an application-managed environment, you need to tweak your code a little bit to turn a class into a singleton, as shown in Listing 7-8. First, you need to prevent the creation of a new instance by having a private constructor. The public static method getInstance() returns the single instance of the CacheSingleton class. If a client class wants to add an object to the cache using the singleton, it needs tocall

CacheSingleton.getInstance().addToCache(myObject);

If you want this code to be thread-safe, you will have to use the synchronized keyword to prevent thread interference and inconsistent data. Instead of a Map, you can also use a java.util.concurrent.ConcurrentMap which will result in much more concurrent and scalable behavior. This can be useful if those are critical considerations.

Listing 7-8.  A Java Class Following the Singleton Design Pattern

public class Cache {
 
  private static Cache instance = new Cache();
  private Map<Long, Object> cache = new HashMap<>();
 
  private Cache() {}
 
  public static synchronized Cache getInstance() {
    return instance;
  }
 
  public void addToCache(Long id, Object object) {
    if (!cache.containsKey(id))
      cache .put(id, object);
  }
 
  public void removeFromCache(Long id) {
    if (cache.containsKey(id))
      cache .remove(id);
  }
 
  public Object getFromCache(Long id) {
    if (cache.containsKey(id))
      return cache .get(id);
    else
      return null;
  }
}

EJB 3.1 introduced the singleton session bean, which follows the singleton design pattern. Once instantiated, the container makes sure there is only one instance of a singleton for the duration of the application. An instance is shared between several clients, as shown in Figure 7-6. Singletons maintain their state between client invocations.

9781430246268_Fig07-06.jpg

Figure 7-6. Clients accessing a singleton bean

image Note  Singletons are not cluster-aware. A cluster is a group of containers that work together closely (sharing the same resources, EJBs, etc.). So, in cases in which several distributed containers cluster together over several machines, each container will have its own instance of the singleton.

To turn the code in Listing 7-8 from a singleton Java class to a singleton session bean (see Listing 7-9), there is not much to do. In fact, you just need to annotate a class with @Singleton and not worry about the private constructor or the static getInstance() method. The container will make sure you create only one instance. The @javax.ejb.Singleton annotation has the same API as the @Stateless annotation described earlier in Listing 7-6.

Listing 7-9.  Singleton Session Bean

@Singleton
public class CacheEJB {
 
  private Map<Long, Object> cache = new HashMap<>();
 
  public void addToCache(Long id, Object object) {
    if (!cache.containsKey(id))
      cache .put(id, object);
  }
 
  public void removeFromCache(Long id) {
    if (cache.containsKey(id))
      cache .remove(id);
  }
 
  public Object getFromCache(Long id) {
    if (cache.containsKey(id))
      return cache .get(id);
    else
      return null;
  }
}

As you can see, stateless, stateful, and singleton session beans are very easy to develop: you just need one annotation. Singletons, though, have a bit more to them. They can be initialized at startup, be chained together, and have their concurrency access customized.

Startup Initialization

When a client class needs to access a method on a singleton session bean, the container makes sure to either instantiate it or use the one already living in the container. However, sometimes initializing a singleton can be time-consuming. Imagine if CacheEJB (shown previously in Listing 7-9) needs to access a database to load its cache with thousands of objects. The first call to the bean will be expensive, and the first client will have to wait for initialization to be completed.

To avoid such latency, you can ask the container to initialize a singleton bean at startup. If the @Startup annotation appears on the bean class, the container initializes it during the application startup, not when a client invokes it. The following code shows you how to use the annotation:

@Singleton
@Startup
public class CacheEJB {...}

image Note  In Java EE 7 the expert group tried to extract the @Startup annotation from the EJB specification so it could be used by any Managed Bean or Servlet. This could not be done, but ideally it is something that will be possible in Java EE 8.

Chaining Singletons

In some cases, when you have several singleton beans, explicit initialization ordering can be important. Imagine if the CacheEJB needs to store data that come from another singleton bean (let’s say a CountryCodeEJB that returns all the ISO country codes). The CountryCodeEJB then needs to be initialized before the CacheEJB. Dependencies can exist between multiple singletons, and the @javax.ejb.DependsOn annotation is there to express it. The following example illustrates the use of the annotation:

@Singleton
public class CountryCodeEJB {...}
 
@DependsOn (" CountryCodeEJB ")
@Singleton
public class CacheEJB {...}

@DependsOn holds one or more Strings, where each specifies the name of the target singleton bean. The following code shows how CacheEJB depends on the initialization of CountryCodeEJB and ZipCodeEJB. @DependsOn("CountryCodeEJB", "ZipCodeEJB") tells the container to guarantee that singleton CountryCodeEJB and ZipCodeEJB are initialized before CacheEJB.

@Singleton
public class CountryCodeEJB {...}
 
@Singleton
public class ZipCodeEJB {...}
@DependsOn (" CountryCodeEJB ", "ZipCodeEJB")
@Startup
@Singleton
public class CacheEJB {...}

As you can see in this code, you can even combine dependencies with startup initialization. CacheEJB is eagerly initialized at startup (because it holds the @Startup annotation), and therefore CountryCodeEJB and ZipCodeEJB will also be initialized at startup before CacheEJB.

You can also use fully qualified names to refer to a singleton packaged within a different module in the same application. Let’s say that both CacheEJB and CountryCodeEJB are packaged in the same application (same ear file) but in different jar files (respectively, technical.jar and business.jar). The following code shows how CacheEJB would depend on CountryCodeEJB:

@DependsOn(" business.jar# CountryCodeEJB")
@Singleton
public class CacheEJB {...}

Note that this kind of reference introduces a code dependency on packaging details (in this case, the names of the module files).

Concurrency

As you understand by now, there is only one instance of a singleton session bean shared by multiple clients. So concurrent access by clients is allowed and can be controlled with the @ConcurrencyManagement annotation in two different ways.

  • Container-managed concurrency (CMC): The container controls concurrent access to the bean instance based on metadata (annotation or the XML equivalent).
  • Bean-managed concurrency (BMC): The container allows full concurrent access and defers the synchronization responsibility to the bean.

If no concurrency management is specified, the CMC demarcation is used by default. A singleton bean can be designed to use either CMC or BMC, but not both. As you’ll see in the following sections, you can use the @AccessTimeout annotation to disallow concurrency (i.e., if a client invokes a business method that is being used by another client, the concurrent invocation will result in a ConcurrentAccessException).

Container-Managed Concurrency

With CMC, the default demarcation, the container is responsible for controlling concurrent access to the singleton bean instance. You can then use the @Lock annotation to specify how the container must manage concurrency when a client invokes a method. The annotation can take the value READ (shared) or WRITE (exclusive).

  • @Lock(LockType.WRITE): A method associated with an exclusive lock will not allow concurrent invocations until the method’s processing is completed. For example, if a client C1 invokes a method with an exclusive lock, client C2 will not be able to invoke the method until C1 has finished.
  • @Lock(LockType.READ): A method associated with a shared lock will allow any number of other concurrent invocations to the bean’s instance. For example, two clients, C1 and C2, can access simultaneously a method with a shared lock.

The @Lock annotation can be specified on the class, the methods, or both. Specifying on the class means that it applies to all methods. If you do not specify the concurrency locking attribute, it is assumed to be @Lock(WRITE) by default. The code in Listing 7-10 shows CacheEJB with a WRITE lock in the bean class. This implies that all methods will have WRITE concurrency except getFromCache(), which is overridden by READ.

Listing 7-10.  A Singleton Session Bean with CMC

@Singleton
@Lock(LockType.WRITE)
@AccessTimeout(value = 20, unit = TimeUnit.SECONDS)
public class CacheEJB {
 
  private Map<Long, Object> cache = new HashMap<>();
 
  public void addToCache(Long id, Object object) {
    if (!cache.containsKey(id))
      cache.put(id, object);
  }
 
  public void removeFromCache(Long id) {
    if (cache.containsKey(id))
      cache.remove(id);
  }
 
  @Lock(LockType.READ)
  public Object getFromCache(Long id) {
    if (cache.containsKey(id))
      return cache.get(id);
    else
      return null;
  }
}

In Listing 7-10, the class has an @AccessTimeout annotation. When a concurrent access is blocked, a timeout can be specified to reject a request if the lock is not acquired within a certain time. If a addToCache() invocation is locked for more than 20 seconds, the client will get a ConcurrentAccessTimeoutException.

Bean-Managed Concurrency

With BMC demarcation, the container allows full concurrent access to the singleton bean instance. You are then responsible for guarding its state against synchronization errors due to concurrent access. In this case, you are allowed to use Java synchronization primitives such as synchronized and volatile. The code in Listing 7-11 shows CacheEJB with BMC (@ConcurrencyManagement(BEAN)) using the synchronized keyword on the addToCache() and removeFromCache() methods.

Listing 7-11.  A Singleton Session Bean with BMC

@Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class CacheEJB {
 
  private Map<Long, Object> cache = new HashMap<>();
 
  public synchronized void addToCache(Long id, Object object) {
    if (!cache.containsKey(id))
      cache.put(id, object);
  }
 
  public synchronized void removeFromCache(Long id) {
    if (cache.containsKey(id))
      cache.remove(id);
  }
 
  public Object getFromCache(Long id) {
    if (cache.containsKey(id))
      return cache.get(id);
    else
      return null;
  }
}

Concurrent Access Timeouts and Not Allowing Concurrency

A concurrent access attempt that cannot immediately acquire the appropriate lock is blocked until it can make forward progress. @AccessTimeout is used to specify the duration that the access attempt should be blocked before timing out. An @AccessTimeout value of -1 indicates that the client request will block indefinitely until forward progress can be made. An @AccessTimeout value of 0 indicates that concurrent access is not allowed. This will result in throwing a ConcurrentAccessException if a client invokes a method that is currently being used. This can have performance implications, as clients might have to handle the exception, try again to access the bean, potentially receive another exception, try again, and so on. In Listing 7-12, CacheEJB disallows concurrency on the addToCache() method. This means that if client A is adding an object to the cache and client B wants to do the same thing at the same time, client B will get an exception and will have to try again later (or manage the exception in another way).

Listing 7-12.  A Singleton Session Bean Not Allowing Concurrency on a Method

@Singleton
public class CacheEJB {
 
  private Map<Long, Object> cache = new HashMap<>();
 
  @AccessTimeout(0)
  public void addToCache(Long id, Object object) {
    if (!cache.containsKey(id))
      cache.put(id, object);
  }
 
  public void removeFromCache(Long id) {
    if (cache.containsKey(id))
      cache.remove(id);
  }
 
  @Lock(LockType.READ)
  public Object getFromCache(Long id) {
    if (cache.containsKey(id))
      return cache.get(id);
    else
      return null;
  }
}

Dependency Injection

I’ve already talked about dependency injection in this book, and you will come across this mechanism several times in the next chapters. It is a simple yet powerful mechanism used by Java EE 7 to inject references of resources into attributes. Instead of the application looking up resources in JNDI, the container injects them. Injection is made at deployment time. If there is a chance that the data will not be used, the bean can avoid the cost of resource injection by performing a JNDI lookup. JNDI is an alternative to injection; through JNDI, the code pulls data only if they are needed, instead of accepting pushed data that may not be needed at all.

The containers can inject various types of resources into session beans using different annotations (or deployment descriptors).

  • @EJB: Injects a reference of the local, remote, or no-interface view of an EJB into the annotated variable.
  • @PersistenceContext and @PersistenceUnit: Expresses a dependency on an EntityManager and on an EntityManagerFactory, respectively (see the section “Obtaining an Entity Manager” in Chapter 6).
  • @WebServiceRef: Injects a reference to a web service.
  • @Resource: Injects several resources such as JDBC data sources, session context, user transactions, JMS connection factories and destinations, environment entries, the timer service, and so on.
  • @Inject: Injects nearly everything with @Inject and @Produces,as explained in Chapter 2.

Listing 7-13 shows a snippet of a stateless session bean using various annotations to inject different resources into attributes. Note that these annotations can be set on instance variables as well as on setter methods.

Listing 7-13.  A Stateless Bean Using Injection

@Stateless
public class ItemEJB {
 
  @PersistenceContext (unitName = "chapter07PU")
  private EntityManager em;
 
  @EJB
  private CustomerEJB customerEJB;
 
  @Inject
  private NumberGenerator generator;
 
  @WebServiceRef
  private ArtistWebService artistWebService;
 
  private SessionContext ctx;
 
  @Resource
  public void setCtx(SessionContext ctx) {
    this.ctx = ctx;
  }
 
  //...
}

Session Context

Session beans are business components that live in a container. Usually, they don’t access the container or use the container services directly (transaction, security, dependency injection, etc.). These services are meant to be handled transparently by the container on the bean’s behalf (this is called inversion of control). However, it is sometimes necessary for the bean to explicitly use container services in code (such as explicitly marking a transaction to be rolled back). And this can be done through the javax.ejb.SessionContext interface. The SessionContext allows programmatic access to the runtime context provided for a session bean instance. SessionContext extends the javax.ejb.EJBContext interface. Table 7-3 describes some methods of the SessionContext API.

Table 7-3. Some Methods of the SessionContext Interface

Method Description
getCallerPrincipal Returns the java.security.Principal associated with the invocation.
getRollbackOnly Tests whether the current transaction has been marked for rollback.
getTimerService Returns the javax.ejb.TimerService interface. Only stateless beans and singletons can use this method. Stateful session beans cannot be timed objects.
getUserTransaction Returns the javax.transaction.UserTransaction interface to demarcate transactions. Only session beans with bean-managed transaction (BMT) can use this method.
isCallerInRole Tests whether the caller has a given security role.
lookup Enables the session bean to look up its environment entries in the JNDI naming context.
setRollbackOnly Allows the bean to mark the current transaction for rollback.
wasCancelCalled Checks whether a client invoked the cancel() method on the client Future object corresponding to the currently executing asynchronous business method.

As shown in Listing 7-14, a session bean can have access to its environment context by injecting a reference of SessionContext with an @Resource annotation. Here the createBook method checks that only admins can create a book. It also rolls back if the inventory level of books is too high.

Listing 7-14.  A Stateless Bean Accessing the SessionContext API

@Stateless
public class ItemEJB {
 
  @PersistenceContext(unitName = "chapter07PU")
  private EntityManager em;
 
  @Resource
  private SessionContext context ;
 
  public Book createBook(Book book) {
 
    if (! context .isCallerInRole("admin"))
      throw new SecurityException("Only admins can create books");
 
    em.persist(book);
 
    if (inventoryLevel(book) == TOO_MANY_BOOKS)
      context .setRollbackOnly();
 
    return book;
  }
}

Asynchronous Calls

By default, session bean invocations through remote, local, and no-interface views are synchronous: a client invokes a method, and it gets blocked for the duration of the invocation until the processing has completed, the result is returned, and the client can carry on its work. But asynchronous processing is a common requirement in many applications handling long-running tasks. For example, printing an order can be a very long task depending on whether the printer is online, there is enough paper, or dozens of documents are already waiting to be printed in the printer’s spool. When a client calls a method to print a document, it wants to trigger a fire-and-forget process that will print the document so the client can carry on its processing.

Before EJB 3.1, asynchronous processing could only be handled by JMS and MDBs (see Chapter 13). You had to create administrated objects (JMS factories and destinations), deal with the low-level JMS API to send a message to a destination, and then develop an MDB that would consume and process the message. JMS comes with good reliability mechanisms (persistent message storage, delivery guarantees, integration with other systems, etc.) but it could be heavyweight for some use cases when you just want to call a method asynchronously.

Since EJB 3.1, you can call methods asynchronously simply by annotating a session bean method with @javax.ejb.Asynchronous. Listing 7-15 shows an OrderEJB that has one method for sending an e-mail to a customer and another for printing the order. Since these two methods are time-consuming, they are both annotated with @Asynchronous.

Listing 7-15.  An OrderEJB That Declares Asynchronous Methods

@Stateless
public class OrderEJB {
 
  @Asynchronous
  public void sendEmailOrderComplete(Order order, Customer customer) {
    // Very Long task
  }
 
  @Asynchronous
  public void printOrder(Order order) {
    // Very Long task
  }
}

When a client invokes either the printOrder() or sendEmailOrderComplete() method, the container returns control to the client immediately and continues processing the invocation on a separate thread of execution. As you can see in Listing 7-15, the return type of the two asynchronous methods is void. This might be suitable in a vast majority of use cases, but sometimes you need a method to return a value. An asynchronous method can return void as well as a java.util.concurrent.Future<V> object, where V represents the result value. Future objects allow you to obtain a return value from a method executed in a separate thread. The client can then use the Future API to get the result or even cancel the call.

Listing 7-16 shows an example of a method that returns a Future<Integer>. The sendOrderToWorkflow() method uses a workflow to process an Order object. Let’s imagine that it calls several enterprise components (messages, web services, etc.), and each step returns a status (an integer). When the client invokes the sendOrderToWorkflow() method asynchronously, it expects to receive the status of the workflow. The client can retrieve the result using the Future.get() method, or, if for any reason it wants to cancel the call, it can use Future.cancel(). If a client invokes Future.cancel(), the container will attempt to cancel the asynchronous call only if that call has not already started. Notice that the sendOrderToWorkflow() method uses the SessionContext.wasCancelCalled() method to check whether the client has requested to cancel the call or not. As a result, the method returns javax.ejb.AsyncResult<V>, which is a convenient implementation of Future<V>. Bear in mind that AsyncResult is used as a way to pass the result value to the container, not directly to the caller.

Listing 7-16.  An Asynchronous Method Returning a Future

@Stateless
@Asynchronous
public class OrderEJB {
 
  @Resource
  SessionContext ctx ;
 
  public Future<Integer> sendOrderToWorkflow(Order order) {
    Integer status = 0;
 
    // processing
    status = 1;
 
    if ( ct x. wasCancelCalled() ) {
      return new AsyncResult<>(2);
    }
 
    // processing
 
    return new AsyncResult<>(status);
  }
}

Notice in Listing 7-16 that you can also apply the @Asynchronous annotation at the class level. This defines all methods as being asynchronous. When the client invokes the sendOrderToWorkflow() method, it needs to call Future.get() in order to retrieve the result value.

Future<Integer> status = orderEJB.sendOrderToWorkflow (order);
Integer statusValue = status. get() ;

Deployment Descriptor

Java EE 7 components use configuration by exception, which means that the container, the persistence provider, or the message broker will apply a set of default services to that component. Configuring these default services is the exception. If you desire nondefault behavior, you need to explicitly specify an annotation, or its counterpart in XML. That’s what you’ve already seen with JPA entities, where a set of annotations allows you to customize the default mapping. The same principle applies for session beans. A single annotation (@Stateless, @Stateful, etc.) is enough to inform the container to apply certain services (transaction, life cycle, security, interceptors, concurrency, asynchrony, etc.), but, if you need to change them, you use annotations or XML. Annotations attach additional information to a class, an interface, a method, or a variable, and so does an XML deployment descriptor.

An XML deployment descriptor is an alternative to annotations, which means that any annotation has an equivalent XML tag. If both annotations and deployment descriptors are used, the settings in the deployment descriptor will override the annotations during deployment process. I will not go into too much detail describing the structure of the XML deployment descriptor (called ejb-jar.xml), as it is optional and can end up being very verbose. As an example, Listing 7-17 shows what the ejb-jar.xml file of ItemEJB could look like (shown previously in Listing 7-2). It defines the bean class, the remote and local interface, its type (Stateless), and that it uses container-managed transaction (CMT) (Container).

Listing 7-17.  The ejb-jar.xml File

<ejb-jar xmlns=" http://xmlns.jcp.org/xml/ns/javaee "
         xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
         xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd "
         version="3.2">
 
  <enterprise-beans>
    <session>
      <ejb-name>ItemEJB</ejb-name>
      <remote>org.agoncal.book.javaee7.chapter07.ItemRemote</remote>
      <local>org.agoncal.book.javaee7.chapter07.ItemLocal</local>
      <local-bean/>
      <ejb-class>org.agoncal.book.javaee7.chapter07.ItemEJB</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
</ejb-jar>

If you deploy the session bean in a jar file, you need to store the deployment descriptor in the META-INF/ejb-jar.xml file. If you deploy it in a war file, you need to store it in the WEB-INF/ejb-jar.xml file. XML configuration is useful for details that are environment-specific and shouldn’t be specified in the code through annotations (e.g., if an EJB needs to be run one way in development and another in test/production environments).

Environment Naming Context

When you work with enterprise applications, there are some situations where parameters of your application change from one deployment to another (depending on the country you are deploying in, the version of the application, etc.). For example, in the CD-BookStore application, ItemEJB (see Listing 7-18) converts the price of an item to the currency of the country where the application is deployed (applying a change rate based on the dollar). If you deploy this stateless bean somewhere in Europe, you need to multiply the price of the item by 0.80 and change the currency to euros.

Listing 7-18.  A Stateless Session Bean Converting Prices to Euros

@Stateless
public class ItemEJB {
 
  public Item convertPrice(Item item) {
    item.setPrice(item.getPrice() * 0.80F );
    item.setCurrency(" Euros ");
    return item;
  }
}

As you can understand, the problem of hard-coding these parameters is that you have to change your code, recompile it, and redeploy the component for each country in which the currency changes. The other option is to access a database each time you invoke the convertPrice() method. That’s wasting resources. What you really want is to store these parameters somewhere you can change them at deployment time. The deployment descriptor is the perfect place to set these parameters.

The deployment descriptor (ejb-jar.xml) might be optional in EJB 3.2, but its use is legitimate with environment entries. Environment entries are specified in the deployment descriptor and are accessible via dependency injection (or via JNDI). They support the following Java types: String, Character, Byte, Short, Integer, Long, Boolean, Double, and Float. Listing 7-19 shows the ejb-jar.xml file of ItemEJB defining two entries: currencyEntry of type String with the value Euros and a changeRateEntry of type Float with the value 0.80.

Listing 7-19.  ItemEJB Environment Entries in ejb-jar.xml

<ejb-jar xmlns=" http://xmlns.jcp.org/xml/ns/javaee "
         xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance "
         xsi:schemaLocation=" http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/ejb-jar_3_2.xsd "
         version="3.2">
 
  <enterprise-beans>
    <session>
      <ejb-name>ItemEJB</ejb-name>
      <env-entry>
        <env-entry-name> currencyEntry </env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>Euros</env-entry-value>
      </env-entry>
      <env-entry>
        <env-entry-name> changeRateEntry </env-entry-name>
        <env-entry-type>java.lang.Float</env-entry-type>
        <env-entry-value>0.80</env-entry-value>
      </env-entry>
    </session>
  </enterprise-beans>
</ejb-jar>

Now that the parameters of the application are externalized in the deployment descriptor, ItemEJB can use dependency injection to get the value of each environment entry. In Listing 7-20, @Resource(name = "currencyEntry") injects the value of the currencyEntry into the currency attribute. Note that the datatypes of the environment entry and the injected variable must be compatible; otherwise, the container throws an exception.

Listing 7-20.  An ItemEJB Using Environment Entries

@Stateless
public class ItemEJB {
 
  @Resource(name = " currencyEntry ")
  private String currency;
  @Resource(name = " changeRateEntry ")
  private Float changeRate;
 
  public Item convertPrice(Item item) {
    item.setPrice(item.getPrice() * changeRate );
    item.setCurrency( currency );
    return item;
  }
}

Packaging

Like most Java EE components (Servlets, JSF pages, web services, etc.); EJBs need to be packaged before they are deployed into a runtime container. In the same archive, you will usually find the enterprise bean class, its interfaces, any needed superclasses or superinterfaces, exceptions, helper classes, and an optional deployment descriptor (ejb-jar.xml). Once you package these artifacts in a jar (Java archive) file, you can deploy them directly into a container. Another option is also to embed the jar file into an ear (enterprise archive) file and deploy the ear file.

An ear file is used to package one or more modules (EJB jars or web applications) into a single archive so that deployment into an application server happens simultaneously and coherently. For example, as shown in Figure 7-7, if you need to deploy a web application, you might want to package your EJBs and entities into separate jar files, your Servlets into a war file, and the whole thing into an ear file. Deploy the ear file into an application server, and you will be able to manipulate entities from the Servlet using the EJB.

9781430246268_Fig07-07.jpg

Figure 7-7. Packaging EJBs

Since EJB 3.1, EJB Lite can also be directly packaged within a web module (war file). On the right side of Figure 7-7, the Servlet, the EJB, and the entity are all packaged within the same war file with all the deployment descriptors. Note that in the EJB module the deployment descriptor is stored under META-INF/ejb-jar.xml and under WEB-INF/ejb-jar.xml for the web module. EJB Lite can be packaged directly in a war or in a jar file. If you need to use the full EJB specification (e.g., remote interface, JMS, asynchronous calls . . .), you have to package it into a jar, not in a war.

Deploying an EJB

Session beans are container-managed components, and that’s their advantage. The container deals with all sorts of services (transaction, life cycle, asynchrony, interceptors, etc.), which leaves you to concentrate on business code. The downside is that you always need to execute your EJBs in a container. Historically these containers were running in a seperate process, so testing was a bit cumbersome. You had to start your container (a.k.a. server), package your EJBs, deploy them, test them, and eventually stop the server . . . to restart it later.

This problem has been solved since EJB 3.1 with the creation of an embeddable EJB container. EJB 3.1 brought a standard API to execute EJBs in a Java SE environment. The embeddable API (package javax.ejb.embeddable) allows a client to instantiate an EJB container that runs within its own JVM. The embeddable container provides a managed environment with support for the same basic services that exist within a Java EE container: injection, transactions, life cycle, and so forth. Embeddable EJB containers only work with the EJB Lite subset API (no MDBs, no remote calls, etc.), meaning it has the same capabilities as an EJB Lite container (but not a full EJB container).

Listing 7-21 shows a main class that uses the bootstrapping API to start the container (the javax.ejb.embeddable.EJBContainer abstract class), looks up an EJB, and invokes methods on it.

Listing 7-21.  A Main Class Using the Embeddable Container

public class Main {
 
  public static void main(String[] args) throws NamingException {
 
    // Sets the container classpath
    Map<String, Object> properties = new HashMap<>();
    properties.put(EJBContainer.MODULES, new File("target/classes"));
 
    // Creates an Embedded Container and get the JNDI context
    try ( EJBContainer ec = EJBContainer.createEJBContainer(properties) ) {
 
      Context ctx = ec.getContext();
 
      // Creates an instance of book
      Book book = new Book();
      book.setTitle("The Hitchhiker's Guide to the Galaxy");
      book.setPrice(12.5F);
      book.setDescription("Science fiction comedy book");
      book.setIsbn("1-84173-742-2");
      book.setNbOfPage(354);
      book.setIllustrations(false);
 
      // Looks up the EJB with the no-interface view
      ItemEJB itemEJB = (ItemEJB) ctx.lookup("java:global/classes/ItemEJB ");
 
      // Persists the book to the database
      itemEJB .createBook(book);
 
      // Retrieves all the books from the database
      for (Book aBook : itemEJB .findBooks()) {
        System.out.println(aBook);
      }
    }
  }
}

As you can see in Listing 7-21, EJBContainer contains a factory method (createEJBContainer()) for creating a container instance. By default, the embeddable container searches the client’s class path to find the set of EJBs for initialization (or you can set the class path using properties). Once you have initialized the container, the application gets the container JNDI context (EJBContainer.getContext(), which returns a javax.naming.Context) to look up the ItemEJB (using the portable global JNDI name syntax).

Note that ItemEJB (shown earlier in Listing 7-1) is a stateless session bean exposing business methods through a no-interface view. It uses injection, container-managed transactions, and a JPA Book entity. The embeddable container takes care of injecting an entity manager and committing or rolling back any transaction. EJBContainer implements java.lang.AutoCloseable so the try-with-resources block will automatically invoke the EJBContainer.close() method to shut down the embeddable container instance.

In Listing 7-21 I’ve used a main class to show you how to use an embeddable EJB container. But bear in mind that EJBs can now be used in any kind of Java SE environment: from test classes to Swing applications, or even batch processing.

Invoking Enterprise Java Beans

Now that you have seen examples of session beans and their different interfaces, you might want to take a look at how the client invokes these beans. The client of a session bean can be any kind of component: a POJO, a graphical interface (Swing), a CDI Managed Bean, a Servlet, a JSF-backing bean, a web service (SOAP or REST), or another EJB (deployed in the same or a different container).

Simplicity also is applied to the client side. To invoke a method on a session bean, a client does not directly instantiate the bean (using the new operator). It needs a reference to the bean (or to its interfaces). It can obtain it via dependency injection (with the @EJB or @Inject annotation) or via JNDI lookup. Dependency injection allows a container to automatically inject a reference on an EJB at deployment time. Unless specified, a client invokes a session bean synchronously.

Invoking with Injection

Java EE uses several annotations to inject references of resources (@Resource), entity managers (@PersistenceContext), web services (@WebServiceRef), and so on. But the @javax.ejb.EJB annotation is specifically intended for injecting session bean references into client code. Dependency injection is only possible within managed environments such as EJB containers, web containers, and application-client containers.

Let’s take our initial examples in which session beans had no interface. For a client to invoke a session bean’s no-interface view, it needs to obtain a reference to the bean class itself. For example, in the following code, the client gets a reference to the ItemEJB class using the @EJB annotation:

@Stateless
public class ItemEJB {...}
 
// Client code injecting a reference to the EJB
@EJB ItemEJB itemEJB;

If the session bean implements several interfaces, the client has to specify which one it wants a reference to. In the following code, the ItemEJB implements two interfaces and, thanks to the @LocalBean annotation, also exposes a no-interface view. The client can invoke the EJB through its local, remote, or no interface:

@Stateless
@Remote( ItemRemote.class )
@Local( ItemLocal.class )
@LocalBean
public class ItemEJB implements ItemLocal , ItemRemote {...}
 
// Client code injecting several references to the EJB or interfaces
@EJB ItemEJB itemEJB;
@EJB ItemLocal itemEJBLocal;
@EJB ItemRemote itemEJBRemote;

The @EJB API has several attributes; one of them is the JNDI name of the EJB you want to inject. This can be useful especially with remote EJBs living in a different server:

@EJB( lookup = "java:global/classes/ItemEJB" ) ItemRemote itemEJBRemote;

Invoking with CDI

As you just saw, invoking a method on an EJB requires only the annotation @EJB to get a reference injected to the client. It is pretty straightforward: it gives you a reference at deployment time. But @EJB doesn’t give you something similar to CDI alternatives, for example. Instead you need to use the @Inject annotation.

Most of the time you can just replace @EJB by @Inject and your client code will work. By doing that you get all the CDI benefits you saw in Chapter 2. So if we take the previous examples, following is how a client would get EJB injection with CDI:

@Stateless
@Remote( ItemRemote.class )
@Local( ItemLocal.class )
@LocalBean
public class ItemEJB implements ItemLocal , ItemRemote {...}
 
// Client code injecting several references to the EJB or interfaces with @Inject
@ Inject ItemEJB itemEJB;
@ Inject ItemLocal itemEJBLocal;
@ Inject ItemRemote itemEJBRemote;

For remote EJBs, as you just saw, you might need to use a JNDI string to look it up. The @Inject annotation cannot have a String parameter, so in this case, you need to produce the remote EJB to be able to inject it:

// Code producing a remote EJB
@Produces @EJB(lookup = "java:global/classes/ItemEJB") ItemRemote itemEJBRemote;
 
// Client code injecting the produced remote EJB
@ Inject ItemRemote itemEJBRemote;

Depending on your client environment, you might not be able to use injection (if the component is not managed by a container). In this case, you can use JNDI to look up session beans through their portable JNDI name.

Invoking with JNDI

Session beans can also be looked up using JNDI. JNDI is mostly used for remote access when a client is not container managed and cannot use dependency injection. But JNDI can also be used by local clients, even if dependency injection results in simpler code. Injection is made at deployment time. If there is a chance that the data will not be used, the bean can avoid the cost of resource injection by performing a JNDI lookup. JNDI is an alternative to injection; through JNDI, the code pulls data only if they are needed, instead of accepting pushed data that may not be needed at all.

JNDI is an API for accessing different kinds of directory services, allowing clients to bind and look up objects via a name. JNDI is defined in Java SE and is independent of the underlying implementation, which means that you can look up objects in a Lightweight Directory Access Protocol (LDAP) directory or a Domain Name System (DNS) using a standard API.

The alternative to the preceding code is to use the InitialContext of JNDI and look up a deployed EJB using its portable JNDI name that I defined earlier in the section “Portable JNDI Name.” The client code looks like the following:

Context ctx = new InitialContext();
ItemRemote itemEJB = (ItemRemote)
        ctx.lookup ("java:global/cdbookstore/ItemEJB!org.agoncal.book.javaee7.ItemRemote");

Summary

Starting with EJB 2.x, the EJB specification has evolved over the years since its creation from a heavyweight model where home and remote/local interfaces had to be packaged with tons of XML to a simple Java class with no interface and one annotation. The underlying functionality is always the same: transactional and secure business logic (more on that in the next chapters).

Session beans are container-managed components that are used to develop business layers. There are three different types of session beans: stateless, stateful, and singleton. Stateless beans are easily scalable because they keep no state, live in a pool, and process tasks that can be completed in a single method call. Stateful beans have a one-to-one correlation with a client and can be temporarily cleared from memory using passivation and activation. Singletons have a unique instance shared among several clients and can be initialized at startup time, chained together, and customized in their concurrency access.

Despite these differences, session beans share a common programming model. They can have a local, remote, or no-interface view, use annotations, or be deployed with a deployment descriptor. Session beans can use dependency injection to get references to several resources (JDBC datasources, persistence context, environment entries, etc.), as well as their runtime environment context (the SessionContext object). Since EJB 3.1, you can invoke methods asynchronously, look up EJBs with a portable JNDI name, or use the embeddable EJB container in the Java SE environment. EJB 3.2 follows the trajectory of its predecessor by bringing some minor enhancements.

The next chapter explains the life cycle of the different session beans and how you can interact with callback annotations. It also shows you how to use the enhanced timer service to schedule tasks and how to set security authorization.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.199.184