CHAPTER 2

image

EJB Session Beans

This chapter will discuss EJB session beans, the core business service objects used by EJB client applications. You’ll gain an understanding of the simplified EJB session bean model with insights into the following topics:

  • Types of session beans—stateful, stateless, and singleton—and when to use each one
  • The bean class, business interfaces, and business methods
  • Asynchronous methods
  • Callback methods
  • Interceptors
  • Exception handling
  • Client view
  • Dependency injection with annotations related to session beans
  • Timer service

Introduction to Session Beans

Session beans are Java components that run either in stand-alone EJB containers or in EJB containers that are part of standard Java Platform, Enterprise Edition (Java EE) application servers. These Java components are typically used to model a particular user task or use case, such as entering customer information or implementing a process that maintains a conversation state with a client application. Session beans can hold the business logic for many types of applications, such as human resources, order entry, and expense reporting applications. The EJB container provides services to the session bean, and the bean indicates which services it needs using Java annotations and/or XML metadata.

Types of Session Beans

Session beans are of three types:

  • Stateless: This type of bean does not maintain any conversational state on behalf of a client application.
  • Stateful: This type of bean maintains a state, and a particular instance of the bean is associated with a specific client request. Stateful beans can be seen as extensions to client programs, which are running on the server.
  • Singleton: This type of bean is instantiated only once per application. Singleton beans live for the full duration of the application and maintain their state between client invocations.

We will drill down into more specifics of stateless, stateful, and singleton beans in the following sections.

When Do You Use Session Beans?

Session beans are used to write business logic, maintain a conversation state for the client, and model back-end processes or user tasks that perform one or more business operations. Typical examples include the following:

  • A session bean in a human resources application that creates a new employee and assigns the employee to a particular department
  • A session bean in an expense reporting application that creates a new expense report
  • A session bean in an order entry application that creates a new order for a particular customer
  • A session bean that manages the contents of a shopping cart in an e-commerce application
  • A session bean that leverages transaction services in an EJB container (removing the need for an application developer to write the transaction support)
  • A session bean used to address deployment requirements when the client applications are not collocated on the same server
  • A session bean that leverages the security support provided by the container on the component or method level
  • A session bean that implements logging functionality and is shared between different components of an application

Session beans can be used in traditional 2-tier or 3-tier architectures with professional/rich client applications, or in 3-tier web-based applications. These applications can be deployed in different logical and physical tier combinations. In the next section, we will investigate some of the possible combinations.

3-Tier Architecture with Rich Client

Figure 2-1 shows a typical architecture for a session bean in 3 tiers with a rich client front-end application that has some data entry screens used by end users, such as customer service representatives, bank tellers, and so on. These client applications can be developed using Java Swing technology with the Java Platform, Standard Edition (Java SE), or they can be plain old Java objects (POJOs), which are run from the command line. Generally, the end user launches the client application from his or her desktop, enters some data, and triggers an event by pressing some user interface component, such as a Submit button. The general workflow may look something like this:

  1. User action establishes a connection to the session bean running in the EJB container using remote method invocation (RMI).
  2. The client application invokes one or more business methods in the session bean.
  3. The session bean processes the request and validates data by interacting with databases, enterprise applications, legacy systems, and so on to perform a certain business operation or task.
  4. Finally, the session bean sends a response back to the client application, either through data collections or simple objects that contain acknowledgment messages.

9781430246923_Fig02-01.jpg

Figure 2-1.  Session beans in a 3-tier architecture with a Rich Client

3-Tier Architecture for a Web Application

This architecture, as shown in Figure 2-2, is typically front-ended by a web application running in the browser of a desktop or laptop computer. These days, other types of client devices, such as smart phones, tablets, cell phones, and telnet devices, are also being used to run these applications. The web application running in a browser or mobile device renders the user interface (data entry screens, submit buttons, and so on) using web technologies such as JavaServer Pages (JSP), JavaServer Faces (JSF), or Java Servlets. Typical user actions, such as entering search criteria or adding certain items to the web application shopping cart, will invoke/call session beans running in an EJB container via one of the aforementioned web technologies. Once the session bean gets invoked, it processes the request and sends a response back to the web application, which formats the response as required and then sends the response on to the requesting client device (browser, smart phone, telnet, and so forth).

9781430246923_Fig02-02.jpg

Figure 2-2.  Session beans in a 3-tier architecture with a web application

In the 3-tier architecture just discussed, the client application (which is the web application) and the session beans can be run within the same instance of an application server (collocated) or from different instances running on the same machine. They can also be run on physically-separate machines that have an instance of an application server.

Stateless Session Beans

Stateless session beans are comprised of the following elements:

  • A bean class, which contains the business method implementation to be executed
  • Optionally, one or more business interfaces, allowing different combinations of the bean’s business methods to be presented to client applications

The Bean Class

A stateless session bean class is any standard Java class that has a class-level annotation of @Stateless. If deployment descriptors are used instead of annotations, then the bean class should be denoted as a stateless session bean in the ejb-jar.xml descriptor. If you use both annotations and deployment descriptors (mixed mode), then the @Stateless annotation must be specified if any other class-level or member-level annotations are specified in the bean class. If both annotations and deployment descriptors are used, then the settings or values in the deployment descriptor will override the annotations in the classes during the deployment process.

image Note   Starting with EJB 3.1, a session bean class can be a sub-class of another session bean class.

To illustrate the use of stateless session beans, we will create a SearchFacade session bean that provides various search facilities to client applications regarding available wines. The workflow is as follows:

  1. Users of the application will type in or choose one or more search criteria, which will be submitted to the SearchFacade session bean.
  2. The SearchFacade bean will access back-end databases to retrieve the requested information. To simplify the code examples in this chapter, we will actually retrieve the list of hard-coded values within the bean class. In later chapters, we will augment the SearchFacade bean to access the back-end database.
  3. The bean returns to the client applications the information that satisfied the search criteria.

Listing 2-1 shows the definition of the SearchFacade bean. In the following sections of this chapter, we will build the code that will show the preceding workflow in action. SearchFacadeBean is a standard Java class with a class-level annotation of @Stateless.

Listing 2-1.  SearchFacadeBean.java

package com.apress.ejb.chapter02;
import javax.ejb.Stateless;
@Stateless(name="SearchFacade")
public class SearchFacadeBean implements SearchFacade, SearchFacadeLocal {
    public SearchFacadeBean() {
    }
}

The Business Interface

A stateless session business interface is a standard Java interface with no other special requirements. This interface has a list of business method definitions that will be available for the client application. A session bean can have a business interface that is implemented by the bean class, generated at design time by tools such as JDeveloper, NetBeans, or Eclipse, or generated at deployment time by the EJB container.

Business interfaces can also use annotations, as described in the following list:

  • The @Remote annotation can be used to denote the remote business interface.
  • The @Local annotation can be used to denote the local business interface.

image Note   Starting with EJB 3.1, session beans support the “no-interface local view.” This is a variation of the local view that exposes public methods of a bean class without a separate business interface.

If no annotation is specified in the interface, then the public methods of the bean class itself become its own de facto local interface.

If your architecture has a requirement whereby the client application (web application or rich client) has to run on a different Java Virtual Machine (JVM) from the one that is used to run the session beans in an EJB container, then you need to use the remote interface. The separate JVMs can be on the same physical machine or on separate machines. If your application architecture is going to use the same JVM for both the client application and the session beans, then performance is improved by using a local interface (which can be the no-interface option).

It is possible that your application architecture requires both remote and local interfaces. For example, an enterprise might have an order entry application that is developed using session beans that have business methods for submitting new orders and also addressing administrative tasks, such as data entry for the products. Potentially, you could have two different client applications that access the back-end order entry application, as follows:

  • A web client application (as shown in Figure 2-3) that can be run in the same JVM as the session bean and used to submit new orders

    9781430246923_Fig02-03.jpg

    Figure 2-3.  A web client using local interfaces of session beans

  • A rich client application (as shown in Figure 2-4) that runs on an end-user desktop machine and is used by the administrator for data entry purposes

    9781430246923_Fig02-04.jpg

    Figure 2-4.  A rich client using remote interfaces of session beans

The SearchFacade session bean has both remote and local interfaces, as shown in Figure 2-5.

9781430246923_Fig02-05.jpg

Figure 2-5.  The business interfaces of the SearchFacade session bean

Listing 2-2 shows the code snippet for the SearchFacade remote business interface with an @Remote annotation and a wineSearch() method declaration. The wineSearch() method takes one parameter that represents the type of the wine, and it returns a list of wines that match the wine type criteria.

Listing 2-2.  SearchFacade.java

package com.apress.ejb.chapter02;
import java.util.List;
import javax.ejb.Remote;

@Remote
public interface SearchFacade {
    List wineSearch(String wineType);
}

Listing 2-3 shows the code snippet for the SearchFacade local business interface with an @Local annotation and a wineSearch() method declaration.

Listing 2-3.  SearchFacadeLocal.java

package com.apress.ejb.chapter02;
import java.util.List;
import javax.ejb.Local;

@Local
public interface SearchFacadeLocal {
    List wineSearch(String wineType);
}

Business Methods

The methods implemented in the bean class must correspond to the business methods declared in the remote or local business interfaces. They are matched up based on the convention that they have the same name and method signature. Other methods in the bean class that do not have the corresponding declaration in the business interfaces will be private to the bean class methods.

The SearchFacade bean implements one method, wineSearch(), which has been declared in both remote and local business interfaces. The wineSearch() method returns a static wines list based on the type of wine. Listing 2-4 shows the implementation for wineSearch().

Listing 2-4.  SearchFacadeBean.java

package com.apress.ejb.chapter02;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;

@Stateless(name="SearchFacade")
public class SearchFacadeBean implements SearchFacade, SearchFacadeLocal {
    public SearchFacadeBean() {
    }

    public List wineSearch(String wineType) {
        List wineList = new ArrayList();
        if (wineType.equals("Red")) {
        wineList.add("Bordeaux");
        wineList.add("Merlot");
        wineList.add("Pinot Noir");
        }
        else if (wineType.equals("White")) {
        wineList.add("Chardonnay");
        }

        return wineList;
    }
}

Asynchronous Business Methods

Asynchronous methods immediately return to the caller without waiting for the method execution to complete. Asynchronous methods are typically used for processor intensive or long-running, background tasks, such as printing a document or sending a large email.

Starting with EJB 3.1, a session bean can declare that one or more of its methods can be executed asynchronously. When a session bean client invokes an asynchronous method, the container immediately returns the control to the client. This allows the client to perform tasks in parallel while the business method completes its execution on a separate thread. For example, clients can use this functionality to show the progress of a long running task using a progress bar.

An asynchronous method is defined by annotating a business method with javax.ejb.Asynchronous annotation. An @Asynchronous annotation at the class level marks all the business methods of the session bean as asynchronous. An asynchronous method must return either void or an implementation of the java.lang.concurrent.Future<V> interface. Asynchronous methods that return void cannot throw application exceptions. Application exceptions can only be thrown by asynchronous methods that return Future<V>.

Asynchronous methods defined on a bean class should have the following signature:

public void <METHOD>(Object)

or

public java.util.concurrent.Future<V> <METHOD>(Object) throws <APPLICATION-EXCEPTION>

Session bean clients invoke asynchronous methods in the same way they invoke synchronous methods. If an asynchronous method has been defined to return a result, the client immediately receives an instance of Future<V> interface. A client can use this instance for any of the following operations:

  • Retrieving the final result set using the get() method. Since this method call blocks synchronously until a result is returned or an exception is thrown, typically it is not called until isDone() returns true.
  • Checking the status of the asynchronous method using the isDone() method
  • Cancelling the method invocation using cancel(boolean) method. Calling cancel() does not interrupt the thread, it simply sets a state flag that can be checked within the running method so that it may gracefully interrupt its execution and return.
  • Checking if the method invocation was cancelled using isCancelled() method
  • Checking for exceptions

image Note   Session bean methods that are exposed as web services can’t be asynchronous.

If an asynchronous method returns a result, it must return that result using the javax.ejb.AsyncResult<V> convenience wrapper object. Note that this object is not actually returned to the client, but is intercepted by the EJB container and unwrapped to service method calls on the Future<V> object that was actually returned to the client when the client invoked the method.

Dependency Injection

In Chapter 1, we introduced the concept of dependency injection as a programming design pattern. In this section, we will take a cursory look into using dependency injection in stateless session beans. Dependency injection is discussed in detail in Chapter 10.

EJB containers provide the facilities to inject various types of resources into stateless session beans. Typically, in order to perform user tasks or process requests from client applications, the business methods in the session bean require one or more types of resources. These resources can be other session beans, data sources, or message queues. Managed beans can be injected into session beans using Contexts and Dependency Injection (CDI).

The resources that the stateless session bean is trying to use can be injected using annotations or deployment descriptors. Resources can be acquired by annotation of instance variables or annotation of the setter methods. Listing 2-5 shows an example of setter and instance variable–based injection of myDb, which represents the data source.

Listing 2-5.  Data Source Injection

@Resource
DataSource myDb;

// or
@Resource
public void setMyDb(DataSource myDb) {
    this.myDb = myDb;
}

You’ll typically use the setter injections to preconfigure or initialize properties of the injected resource.

Lifecycle Callback Methods

There will be certain instances or use cases in which the application using session beans requires fine-grained control over lifecycle events like its own creation, removal, and so on. For example, the SearchFacade session bean might need to perform some database initialization when it is created or close some database connections when it is destroyed. The application can gain fine-grained control over the various stages of the bean lifecycle via methods known as callback methods. A callback method can be any method in the session bean that has callback annotations. The EJB container calls these methods at the appropriate stages of the bean’s lifecycle (bean creation and destruction).

Following are two such callbacks for stateless session beans:

  • PostConstruct: Denoted with the @PostConstruct annotation. Methods on the bean class that use a specific signature, as described below, can be marked with this annotation.
  • PreDestroy: Denoted with the @PreDestroy annotation. Again, any method in the bean class with a specific signature, as described below, can be marked with this annotation.

Callback methods defined on a bean class should have the following signature:

void <METHOD>()

Callback methods can also be defined on a bean’s listener class; these methods should have the following signature:

void <METHOD>(Object)

where Object may be declared as the actual bean type, which is the argument passed to the callback method at run time. Lifecycle callback methods can have public, private, protected, or package level access. A lifecycle callback method must not be declared as final or static.

PostConstruct callbacks happen after a bean instance is instantiated in the EJB container. If the bean is using any dependency injection mechanisms for acquiring references to resources or other objects in its environment, PostConstruct will occur after injection is performed and before the first business method in the bean class is called. In the case of the SearchFacade session bean, you could have a business method, wineSearchByCountry(), which would return the wine list for a particular country and have a PostConstruct callback method, initializeCountryWineList(), that would initialize the country’s wine list whenever the bean gets instantiated. Ideally, you would load the list from a back-end datastore; but in this chapter, we will just use some hard-coded values that get populated into a HashMap, as shown in Listing 2-6.

Listing 2-6.  The PostConstruct Method

@PostConstruct
public void initializeCountryWineList() {
    // countryMap is HashMap
    countryMap.put("Australia", "Sauvignon Blanc");
    countryMap.put("Australia", "Grenache");
    countryMap.put("France","Gewurztraminer");
    countryMap.put("France","Bordeaux");
}

The PreDestroy callback happens before the container destroys an unused or expired bean instance from its object pool. This callback can be used to close any connection pool that has been created with dependency injection and also to release any other resources.

In the case of the SearchFacade session bean, we could add a PreDestroy callback method (destroyWineList()) into the SearchFacade bean, which would clear the country wine list whenever the bean gets destroyed. Ideally, during PreDestroy, we would close any resources that have been created with dependency injection; but in this chapter, we will just clear the HashMap that has the countries and wine list. Listing 2-7 shows the destroyWineList() code.

Listing 2-7.  The PreDestroy Method

@PreDestroy
public void destroyWineList() {
    countryMap.clear();
}

Interceptors

The EJB specification provides annotations called interceptors, which allow you to interpose on a business method invocation to add your own wrapper code before and/or after the method is called. An interceptor method can be defined for session and message-driven beans (MDBs). We will show you the usage of interceptors in the session bean context.

There are number of use cases for interceptors in a typical application in which you would find a need to perform a certain task before or after the business method is invoked. For example, you may wish to do one of the following:

  • Perform additional security checks before a critical business method that transfers more than $100,000 dollars
  • Do some performance analysis to compute the time it takes to perform the task
  • Do additional logging before or after the method invocation

There are two ways to define an interceptor. You can either add an @AroundInvoke annotation on a particular method, or you can annotate the bean class to designate an interceptor class that will interpose on all (or an explicit subset of) methods on the bean class. An interceptor class is denoted by the @Interceptor annotation on the bean class with which it is associated. In the case of multiple interceptor classes, the @Interceptors annotation is used. Method specific interceptor is denoted by applying the @Interceptors annotation to the business method. Methods that are annotated with @AroundInvoke should have the following signature:

Object <METHOD>(InvocationContext) throws Exception

AroundInvoke methods can have public, private, protected, or package level access. An AroundInvoke method must not be declared as final or static. The definition of InvocationContext is as follows:

package javax.ejb;
public interface InvocationContext {
   public Object getBean();
   public java.lang.reflect.Method getMethod();
   public Object[] getParameters();
   public void setParameters(Object[] params);
   public EJBContext getEJBContext();
   public java.util.Map getContextData();
   public Object proceed() throws Exception;
}

The following list describes the methods in the preceding code:

  • getBean() returns the instance of the bean on which the method was called.
  • getMethod() returns the method on the bean instance that was called.
  • getParameters() returns the parameters for the method call.
  • setParameters() modifies the parameters used for the method call.
  • getEJBContext() gives the interceptor methods access to the bean’s EJBContext.
  • getContextData() allows values to be passed between interceptor methods in the same InvocationContext instance using the Map returned.
  • proceed() invokes the next interceptor, if there is one, or invokes the target bean method.

In the SearchFacade session bean, we can add an interceptor that logs the time taken to execute each business method when invoked by the client applications. Listing 2-8 shows a time log method that will print out the time taken to execute a business method. InvocationContext is used to get the name of bean class and the invoked method name. Before invoking the business method, current system time is captured and deducted from the system time after the business method is executed. Finally, the details are printed out to the console log using System.out.println.

Listing 2-8.  The Interceptor Method

@AroundInvoke
public Object TimerLog (InvocationContext ctx) throws Exception {
    String beanClassName = ctx.getClass().getName();
    String businessMethodName = ctx.getMethod().getName();
    String target = beanClassName + "." + businessMethodName ;
    long startTime = System.currentTimeMillis();
    System.out.println ("Invoking " + target);
    try {
        return ctx.proceed();
    }
    finally {
        System.out.println ("Exiting" + target);
        long totalTime = System.currentTimeMillis() - startTime;
        System.out.println ("Business method" + businessMethodName +
        "in" + beanClassName + "takes" + totalTime + "ms to execute");
    }
}

Stateful Session Beans

Similar to stateless session beans, stateful beans comprise a bean class and, optionally, one or more business interfaces.

The Bean Class

A stateful session bean class is any standard Java class that has a class-level annotation of @Stateful. If deployment descriptors are used instead of annotations, the bean class should be denoted as a stateful session bean. In the case of mixed mode, in which you are using annotations and deployment descriptors, the @Stateful annotation must be specified if any other class-level or member-level annotations are specified in the class.

To illustrate a stateful session bean, we will create a ShoppingCart session bean that will keep track of the items added to a user’s shopping cart and their respective quantities. In this chapter, we will use hard-coded values for the shopping cart to illustrate the state and conversation maintenance between the client and stateful session bean. Listing 2-9 shows the definition of a ShoppingCart session bean.

Listing 2-9.  ShoppingCartBean.java

package com.apress.ejb.chapter02;
import javax.ejb.Stateful;
@Stateful(name="ShoppingCart")
public class ShoppingCartBean implements ShoppingCart, ShoppingCartLocal {
    public ShoppingCartBean() {
    }
}

There will be certain use cases in which the application wants to be notified by the EJB container before or after transactions take place and then use these notifications to manage data and cache. A stateful session bean can receive this kind of notification by the EJB container when it implements the javax.ejb.SessionSynchronization interface. This is an optional feature. There are three different types of transaction notifications that the stateful session bean receives from the EJB container:

  • afterBegin: Indicates that a new transaction has begun
  • beforeCompletion: Indicates that the transaction is going to be committed
  • afterCompletion: Indicates that a transaction has been completed

For example, the ShoppingCart session bean could implement the javax.ejb.SessionSynchronization interface to get an afterCompletion notification so that it can clear out the shopping cart cache.

The Business Interface

Business interfaces for stateful session beans are similar to those used for stateless session beans, and they are annotated in the same way, using @Local and @Remote annotations. Local view of stateful session beans can be accessed without a separate local business interface. The ShoppingCart session bean has both remote and local interfaces, as shown in Figure 2-6.

9781430246923_Fig02-06.jpg

Figure 2-6.  Business interfaces for ShoppingCart

We will primarily use the local interface from our web application. The remote interface is added to facilitate unit testing of the bean in this chapter.

Listings 2-10 and 2-11 show the remote and local ShoppingCart business interfaces, with @Remote and @Local annotations, respectively.

Listing 2-10.  ShoppingCart.java

package com.apress.ejb.chapter02;
import javax.ejb.Remote;
@Remote
public interface ShoppingCart {
}

Listing 2-11.  ShoppingCartLocal.java

package com.apress.ejb.chapter02;
import javax.ejb.Local;
@Local
public interface ShoppingCartLocal {
}

Alternatively, you can use the coding style shown in Listing 2-12, in which you can specify the @Local and @Remote annotations before specifying @Stateful or @Stateless with the name of the business interface.

Listing 2-12.  ShoppingCartBean.java

package com.apress.ejb.chapter02;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateful;

@Local({ShoppingCartLocal.class})
@Remote({ShoppingCart.class})
@Stateful(name="ShoppingCart")

public class ShoppingCartBean implements ShoppingCart, ShoppingCartLocal {
    public ShoppingCartBean() {
    }
}

image Note   We will follow the earlier convention in this book, in which @Local and @Remote annotations are marked on the business interfaces.

Business Methods

Business methods in stateful session beans are similar to those in stateless session beans. We will augment the ShoppingCart bean by adding business methods that will add and remove wines from the shopping cart and return a list of cart items.

Listing 2-13 shows the ShoppingCart bean implementing the addWineItem(), removeWineItem(), and getCartItems() methods.

Listing 2-13.  ShoppingCartBean.java

package com.apress.ejb.chapter02;
import java.util.ArrayList;
import javax.ejb.Stateful;

@Stateful(name="ShoppingCart")
public class ShoppingCartBean implements ShoppingCart, ShoppingCartLocal {
    public ShoppingCartBean() {
    }
    public ArrayList cartItems;
    public void addWineItem(String wine) {
       cartItems.add(wine);
    }

    public void removeWineItem(String wine) {
       cartItems.remove(wine);
    }

    public void setCartItems(ArrayList cartItems) {
        this.cartItems = cartItems;
    }

    public ArrayList getCartItems() {
        return cartItems;
    }
}

Lifecycle Callback Methods

Stateful session beans support callback events for construction, destruction, activation, and passivation. Following are the callbacks that map to the preceding events:

  • PostConstruct: Denoted with the @PostConstruct annotation.
  • PreDestroy: Denoted with the @PreDestroy annotation.
  • PreActivate: Denoted with the @PreActivate annotation.
  • PrePassivate: Denoted with the @PrePassivate annotation.

The PostConstruct callback happens after a bean instance is instantiated in the EJB container. If the bean is using any dependency injection mechanism for acquiring references to resources or other objects in its environment, the PostConstruct event happens after injection is performed and before the first business method in the bean class is called.

In the case of the ShoppingCart session bean, we could have a business method called initialize() that initializes the cartItems list, as shown in Listing 2-14.

Listing 2-14.  The PostConstruct Method

@PostConstruct
public void initialize() {
    cartItems = new ArrayList();
}

The PreDestroy callback happens after any method where an @Remove annotation has been completed. In the case of the ShoppingCart session bean, we could have a business method called exit() that writes the cartItems list into a database. In this chapter, we will just print out a message to the system console to illustrate the callback. Listing 2-15 shows the code for the exit() method, which has the @PreDestroy annotation.

Listing 2-15.  The PreDestroy Method

@PreDestroy
public void exit() {
    // items list into the database.
    System.out.println("Saved items list into database");
}

The @Remove annotation is a useful lifecycle method for stateful session beans. When the method with the @Remove annotation is called, the container will remove the bean instance from the object pool after the method is executed. Listing 2-16 shows the code for the stopSession() method, which has the @Remove annotation.

Listing 2-16.  The Remove Method

@Remove
public void stopSession() {
    // The method body can be empty.
    System.out.println("From stopSession method with @Remove annotation");
}

The PrePassivate callback kicks in when a stateful session bean instance is idle for too long. During this event, the container might passivate and store its state to a cache. The method tagged with @PrePassivate is called before the container passivates the bean instance.

The PostActivate event gets raised when the client application again uses a passivated stateful session bean. A new instance with restored state is created. The method with the @PostActivate annotation is called when the bean instance is ready.

Interceptors

There are some minor differences between interceptors for stateless and stateful session beans. AroundInvoke methods can be used with stateful session beans. For stateful session beans that implement SessionSynchronization, afterBegin occurs before any methods that have AroundInvoke annotations and before the beforeCompletion() callback method.

Exception Handling

The EJB specification outlines two types of exceptions:

  • Application exceptions
  • System exceptions

Application exceptions are exceptions related to execution of business logic that the client should handle. For example, an application exception might be raised if the client application passes an invalid argument, such as the wrong credit card number.

System exceptions, on the other hand, are caused by system-level faults, such as Java Naming and Directory Interface (JNDI) errors or failure to acquire a database connection. A system exception must be a subclass of a java.rmi.RemoteException or a subclass of a java.lang.RuntimeException that is not an application exception.

From the EJB application point of view, application exceptions are completed by writing application-specific exception classes that subclass the java.lang.Exception class.

In the case of a system exception, the application catches particular exceptions, such as a NamingException that results from a JNDI failure, and throws an EJBException. In this chapter, the examples aren’t using any resources as such, but there are more examples of system exceptions in the later chapters.

Singleton Session Beans

Introduced in EJB 3.1, a singleton session bean is a session bean component that is instantiated only once per application. For an application, only one instance of a singleton session bean can ever exist. Once instantiated, a singleton session bean lives for the full duration of the application. The singleton session bean maintains its state between client invocations, but it cannot save that state after a container shutdown or crash. Similar to stateless and stateful session beans, the singleton session bean is comprised of a bean class and, optionally, one or more business interfaces.

The Bean Class

A singleton session bean class is any standard Java class that has a class-level annotation of @Singleton. If deployment descriptors are used instead of annotations, the bean class should be denoted as a singleton session bean. If you are using annotations and deployment descriptors (mixed mode), then the @Singleton annotation must be specified if any other class-level or member-level annotations are specified in the class.

To illustrate a singleton session bean, we will create a ShopperCount session bean that will keep track of the number of users logged onto our shopping website. Listing 2-17 shows the definition of the ShopperCount session bean.

Listing 2-17.  ShopperCountBean.java

package com.apress.ejb.chapter02;

import javax.ejb.Singleton;
import javax.ejb.Startup;
@Singleton (name = "ShopperCount")
@Startup
public class ShopperCountBean {
   private int shopperCounter;

   // Increment number of shopper counter
   public void incrementShopperCount() {
       shopperCounter++;
   }

   // Return number of shoppers
   public int getShopperCount() {
       return shopperCounter;
   }
}

A singleton session bean is instantiated at the discretion of the EJB container. However, you can annotate the bean class with @Startup to indicate that the container must initialize the singleton bean during the application startup sequence.

When multiple singleton session beans are used within an application, the application might require that they be initialized in a specific sequence. @DependsOn annotation declares the startup dependencies of a singleton session bean. Listing 2-18 shows the definition of the LogShopperCount session bean that is dependent on the ShopperCount session bean.

Listing 2-18.  LogShopperCount.java

package com.apress.ejb.chapter02;

import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.DependsOn;
import java.util.logging.Logger;

@Singleton
@Startup
@DependsOn("ShopperCount")
public class LogShopperCount {
   private final Logger log = Logger.getLogger("LogShopperCount.class");

   public void logShopperCount() {
       // Log shopper count
   }
}

Unlike stateless and stateful session beans, a singleton session bean must not implement the javax.ejb.SessionSynchronization interface or use session synchronization annotations.

The Business Interface

Business interfaces for singleton session beans are similar to the interfaces for stateless and stateful session beans, and they are annotated in the same way using @Local and @Remote annotations. Singleton session beans support the no-interface local view, making the declaration of a business interface optional for a local view.

Business Methods

Business methods in singleton session beans are similar to the methods in stateless and stateful session beans. We will augment the ShopperCount bean by adding a business method that will reset the counter.

Listing 2-19 shows the ShopperCount bean implementing business methods.

Listing 2-19.  ShopperCountBean.java

package com.apress.ejb.chapter02;

import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton(name = "ShopperCount")
@Startup
public class ShopperCountBean {
   private int shopperCounter = 0;

   // Increment number of shopper counter
   public void incrementShopperCount() {
       shopperCounter++;
   }

   // Return number of shoppers
   public int getShopperCount() {
       return shopperCounter;
   }

   // Reset counter
   public void resetCounter() {
       shopperCounter = 0;
   }
}

Lifecycle Callback Methods

Singleton session beans support callback events for construction and destruction. Following are the callbacks that map to the preceding events:

  • PostConstruct: Denoted with the @PostConstruct annotation
  • PreDestroy: Denoted with the @PreDestroy annotation.

PostConstruct callback happens after a bean instance is instantiated in the EJB container. If the bean is using any dependency injection mechanism for acquiring references to resources or other objects in its environment, the PostConstruct event happens after injection is performed and before the first business method in the bean class is called.

PreDestroy callback happens during application shutdown. The container considers the DependsOn relationship between singleton session beans and removes them in a sequence that is in the reverse order of the sequence in which they were created. For the ShopperCount example, LogShopperCount bean will be removed before the ShopperCount bean.

Listing 2-20 shows the code for the applicationStartup() method with the @PostConstruct annotation. This method resets the shopperCounter on startup. Listing 2-20 also shows the code for the applicationShutdown() method with the @PreDestroy annotation. This method prints a message on application shutdown.

Listing 2-20.  ShopperCountBean.java

package com.apress.ejb.chapter02;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton(name = "ShopperCount")
@Startup
public class ShopperCountBean {
   private int shopperCounter;

   // Increment number of shopper counter
   public void incrementShopperCount() {
       shopperCounter++;
   }

   // Return number of shoppers
   public int getShopperCount() {
       return shopperCounter;
   }

   // Reset counter
   public void resetCounter() {
       shopperCounter = 0;
   }

   // Reset counter
   @PostConstruct
   public void applicationStartup() {
       System.out.println("From applicationStartup method.");
       resetCounter();
   }

   @PreDestroy
   public void applicationShutdown() {
      System.out.println("From applicationShutdown method.");
   }
}

Like a stateless session bean, a singleton session bean is never passivated, so the @PrePassivate and @PostActivate annotations should not be used to decorate methods on a singleton session bean.

Concurrency Management

A singleton session bean is instantiated only once per application, and hence it is designed to support concurrent access. Concurrent access means multiple clients can access the same instance of a singleton session bean at the same time. The management of concurrent access is transparent to the clients. A client needs only a reference to a singleton session bean, and it is unconcerned about other clients accessing the same instance of the singleton session bean.

Concurrency is managed in two ways:

  • Container-Managed concurrency: The container controls concurrent access and allows fine-grained control of the state synchronization behavior by offering a fixed set of options. This is the default concurrency management type.
  • Bean-Managed concurrency: The container allows full access to the concurrent bean instance, and the user is responsible for state synchronization.

The type of concurrency—container-managed or bean-managed—is specified by the javax.ejb.ConcurrencyManagement annotation specified on the singleton session bean class. For container-managed concurrency, the type attribute of @ConcurrencyManagement is set to javax.ejb.ConcurrencyManagementType.CONTAINER; for bean-managed concurrency, the type attribute of @ConcurrencyManagement is set to javax.ejb.ConcurrencyManagementType.BEAN.

Container-Managed Concurrency

For a singleton session bean using container-managed concurrency, the container manages concurrency by associating each business method with either a shared Read lock or an exclusive Write lock. A Read or Write lock is specified using the @Lock annotation.

Listing 2-21 demonstrates container-managed concurrency by using the Read lock on the getShopperCount method and Write lock on the incrementShopperCount method. With this change, multiple clients can get the value of shopperCounter concurrently but access to incrementShopperCount is blocked for all other clients while one client is accessing it.

Listing 2-21.  ShopperCountBean.java

package com.apress.ejb.chapter02;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton(name = "ShopperCount")
@Startup
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class ShopperCountBean {
    private int shopperCounter;
    // Increment number of shopper counter
    @Lock(LockType.WRITE)
    public void incrementShopperCount() {
        shopperCounter++;
    }

    // Return number of shoppers
    @Lock(LockType.READ)
    public int getShopperCount() {
        return shopperCounter;
    }

    // Reset counter
    public void resetCounter() {
        shopperCounter = 0;
    }

    // Reset counter
    @PostConstruct
    public void applicationStartup() {
        resetCounter();
    }

    @PreDestroy
    public void applicationShutdown() {
        System.out.println("From applicationShutdown method.");
    }
}

For a singleton session bean, an @Lock annotation at the class level specifies that all business methods will use the specified lock type unless a different type is explicitly set at the method level. When the @Lock annotation is not explicitly present on the singleton session bean class, the default lock type, @Lock(LockType.WRITE), is applied to all business methods.

Bean-Managed Concurrency

In the case of bean-managed concurrency, the container allows full concurrent access to the singleton session bean instance and the bean developer must provide protection to the bean’s internal state against synchronization errors that result from concurrent access. You can use synchronization primitives like synchronized and volatile for this purpose.

Error Handling

Errors can occur during initialization of a singleton session bean. These errors are fatal and, as a result, the singleton session bean instance must be discarded. Attempted invocations on a singleton session bean instance that failed to initialize will result in the javax.ejb.NoSuchEJBException. Once a singleton session bean is instantiated successfully, it will not be destroyed if exceptions are thrown from either business methods or callbacks.

Timer Service

The EJB Timer Service is a container-managed service that allows callbacks to be scheduled for time-based events. Timer notifications can be scheduled to occur at a calendar based schedule, at a specific time, after a specific time, or at specific recurring intervals.

Use timers for application level processes. Don’t use timers for real-time events. Typical examples of using a timer include the following:

  • A timer in an expense reporting application prints newly filed expenses every evening at 9 PM.
  • A timer in a bug tracking application emails a list of open bugs to team members every morning at 6 AM.
  • A timer in a human resources application emails a list of public holidays to all the employees on the 1st of January every year.

image Note   Timers cannot be created for stateful session beans.

Creating a timer is simplified in EJB 3.1 via introduction of @Schedule and @Schedules annotations that automatically create timers based on metadata specified on a method. In Listing 2-22, we augment our LogShopperCount by adding a recurring timer that will log the shopper count every two hours.

Listing 2-22.  LogShopperCount.java

package com.apress.ejb.chapter02;

import javax.ejb.DependsOn;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
@DependsOn("ShopperCountBean")
public class LogShopperCount {

       // Logs shopper count every 2 hours
       @Schedule(hour="*/2")
       public void logShopperCount() {
       // Log shopper count
       }
}

Pass the Timer object in methods annotated with @Schedule to get information about the timer. Listing 2-23 demonstrates the use of the Timer object to get information about the timer that just expired.

Listing 2-23.  LogShopperCount.java

package com.apress.ejb.chapter02;

import javax.ejb.DependsOn;
import javax.ejb.Schedule;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timer;

@Singleton
@Startup
@DependsOn("ShopperCount")
public class LogShopperCount {

// Logs shopper count every 2 hours
@Schedule(hour="*/2")
public void logShopperCount(Timer timer) {
// Log shopper count
String timerInfo = (String) timer.getInfo();
System.out.println(timerInfo);
}
}

Calendar-Based Time Expressions

The Timer Service is inspired by the UNIX cron utility. Table 2-1 lists the various attributes of a calendar-based time expression.

Table 2-1. Attributes of calendar-based time expression

image

image Note   For dayOfWeek, both 0 and 7 represent Sunday and a negative number (−7 to −1), which means the nth day or days before the end of the month. All string constants (“Sun”, “Jan”, “Last”, “1st”) are case insensitive. Increments are supported only by second, minute, and hour. Duplicate values within a list are ignored.

Examples of Calendar-Based Time Expressions

Let us see some examples that demonstrate the use of calendar-based time expressions.

  • “Every second of every minute of every hour of everyday”
  • @Schedule(second="*", minute="*", hour="*")
  • “Every fifteen minutes within the hour”
  • @Schedule(minute="*/15", hour="*")
  • @Schedule(minute="0, 15, 30, 45", hour="*")
  • “Every Friday at midnight”
  • @Schedule(dayOfWeek="Fri")
  • “Every six hours on weekends”
  • @Schedule(hour="*/6", dayOfWeek="Sat, Sun")
  • “Every weekday morning at 7:30am U.S. Pacific Time”
  • @Schedule(minute="30", hour="7", dayOfWeek="Mon-Fri", timezone="America/Los_Angeles")
  • “On 10th of January and September at 6am”
  • @Schedule(month="Jan, Sep", dayOfMonth="10", hour="6")
  • “Last Friday of December at 6pm”
  • @Schedule(month="Dec", dayOfMonth="Last Fri", hour="18")
  • “Second to last day (one day before the last day) of each month”
  • @Schedule(dayOfMonth="-1")
  • “Every day only for year 2013”
  • @Schedule(year="2013")

Timer Persistence

Timers are persistent. A timer is persisted by the Timer Service by storing it in a database. The database used by the Timer Service can be changed by setting the Timer Service’s Timer DataSource setting to a valid JDBC resource. Persistence helps timers survive application shutdown, container crashes, and container shutdowns.

Persistence can be disabled on a per-timer basis by setting the persistent attribute of the @Schedule annotation to false. A non-persistent timer’s lifetime is associated with the JVM that created it. A non-persistent timer is considered cancelled in the event of application shutdown, container crash, or crash/shutdown of the JVM on which the timer was created.

Client View for Session Beans

A session bean can be seen as a logical extension of a client program or application, where much of the logic and data processing for that application happens. A client application typically accesses the session object through the session bean’s client view interfaces. These are the business interfaces that were discussed in earlier sections.

A client application that accesses session beans can be one of three types:

  • Remote: Remote clients run in a separate JVM from the session beans that they access, as shown in Figure 2-4. A remote client accesses a session bean through the bean’s remote business interface. A remote client can be another EJB, a Java client program, or a Java servlet. Remote clients have location independence, meaning that they can use the same API as the clients running in the same JVM.
  • Local: Local clients run in the same JVM, as shown in Figure 2-3, and access the session bean through the local business interface. A local client can be another EJB, or a web application using Java Servlets, JavaServer Pages (JSP), or JavaServer Faces (JSF). Local clients are location dependent. Remote and local clients are compared in Table 2-2.

    Table 2-2. Considerations for Choosing Between Local and Remote Clients

    Remote Local
    Loose coupling between the bean and the client Lightweight access to a component
    Location independence Location dependence
    Expensive remote calls Must be collocated with the bean
    Objects must be serialized Not required
    Objects are passed by value Objects are passed by reference
  • Web Services: You can publish stateless session beans as web services that can be invoked by Web Services clients. We will discuss Web Services and clients in Chapter 6.

In some cases, the session beans need to have both local and remote business interfaces to support different types of client applications. A client can obtain a session bean’s business interface via dependency injection or JNDI lookup. Before invoking the methods in the session bean, the client needs to obtain a stub object of the bean via JNDI. Once the client has a handle to the stub object, it can call the business methods in the session bean. In the case of a stateless session bean, a new stub can be obtained on every invocation. In the case of a stateful session bean, the stub needs to be cached on the client side so that the container knows which instance of the bean to return on subsequent calls. Using dependency injection, we can obtain the business interface of the SearchFacade session bean with the following code:

@EJB SearchFacade searchFacade;

If the client accessing the session bean is remote, the client can use JNDI lookup once the context interface has been obtained with the right environment properties. Local clients can also use JNDI lookup, but dependency injection results in simpler code. Listing 2-24 shows the SearchFacadeTest client program’s code that looks up the SearchFacade bean, invokes the wineSearch() business method, and prints out the returned list of wines. SearchFacadeClient also looks up the ShopperCount singleton bean and invokes the getShopperCount() business method to print the number of shoppers logged.

image Note   If the remote client is a Java application or command-line program, an application client container can be used to invoke the session beans. Application client containers support dependency injection for remote clients. We will discuss application client containers in Chapter 12, along with other types of client applications.

Listing 2-24.  SearchFacadeClient.java

package com.apress.ejb.chapter02;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "SearchFacadeClient", urlPatterns = {"/SearchFacadeClient"})
public class SearchFacadeClient extends HttpServlet {

    @EJB
    SearchFacadeBean searchFacade;

    @EJB
    ShopperCountBean shopperCount;
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {

            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet SearchFacadeClient</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1> Starting Search Facade test ... </h1>");
            
            out.println("<h1>SearchFacade Lookup</h1>");
            out.println("<h1>Searching wines</h1>");
            List winesList = searchFacade.wineSearch("Red");
            out.println("<h1>Printing wines list</h1>");
            for (String wine:(List<String>)winesList ){
                out.println("<h1>" + wine + "</h1>");
            }

            System.out.println("Printing Shopper Count after incrementing it ...");
            shopperCount.incrementShopperCount();
            out.println("<h1>" + shopperCount.getShopperCount() + "</h1>");
            
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Listing 2-25 shows the ShoppingCartClient servlet, which looks up the stateful ShoppingCart session bean, calls the addWineItem() business method to add a wine to the shopping cart, calls the getCartItems() business method to get the items in the cart, and finally prints the list of wines in the shopping cart.

Listing 2-25.  ShoppingCartClient.java

package com.apress.ejb.chapter02;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ShoppingCartClient", urlPatterns = {"/ShoppingCartClient"})
public class ShoppingCartClient extends HttpServlet {

   @EJB
   ShoppingCartBean shoppingCart;
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet ShoppingCartClient</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h1>Starting Shopping Cart test ... </h1>");
            
            out.println("<h1>ShoppingCart Lookup </h1>");
            out.println("<h1>Adding Wine Item </h1>");
            shoppingCart.addWineItem("Zinfandel");
            out.println("<h1>Printing Cart Items </h1>");
            ArrayList cartItems = shoppingCart.getCartItems();
            for (String wine: (List<String>)cartItems) {
                out.println("<h1>" + wine + "</h1>");
            }
            
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Listing 2-26 shows the ShopperCountClient servlet, which looks up the singleton ShopperCount session bean, calls the resetCounter() business method to reset the shopper count, calls the incrementShopperCount() business method to increment the shopper count, and finally prints the total number of shoppers counted. The value of shopper count will be visible across the application.

Listing 2-26.  ShopperCountClient.java

package com.apress.ejb.chapter02;
import java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "ShopperCountClient", urlPatterns = {"/ShopperCountClient"})
public class ShopperCountClient extends HttpServlet {
    @EJB
    ShopperCountBean shopperCount;
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            /* TODO output your page here. You may use following sample code. */
            out.println("<html>");
            out.println("<head>");
            out.println("<title>Servlet ShopperCountClient</title>");
            out.println("</head>");
            out.println("<body>");

            out.println("<h1>Resetting Shopper Count ... </h1>");
            shopperCount.resetCounter();
            out.println("<h1>Incrementing Shopper Count ... </h1>");
            shopperCount.incrementShopperCount();
            out.println("<h1>Shopper Count: " + shopperCount.getShopperCount() + "</h1>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }
}

Compiling, Deploying, and Testing the Session Beans

Session beans need to be packaged into EJB JAR (.jar) files before they are deployed into EJB containers. In the case of some EJB containers or application servers, packaged EJB archives need to be assembled into Enterprise Archive (EAR) files before deployment. EJB containers or application servers provide deployment utilities or Ant tasks to facilitate deployment of EJBs. Java IDEs (integrated development environments) like JDeveloper, NetBeans, and Eclipse also provide deployment features that allow developers to package, assemble, and deploy EJBs to application servers. Packaging, assembly, and deployment are covered in detail in Chapter 11.

So far in this chapter we have developed one stateless session bean (SearchFacade), one stateful session bean (ShoppingCart), and one singleton session bean (ShopperCount). The following sections will walk you through the steps necessary to compile, deploy, and test these session beans.

Prerequisites

Before performing any of the steps detailed in the next sections, complete the “Getting Started” section of Chapter 1. This section will walk you through the installation and environment setup required for the samples in this chapter.

Compiling the Session Beans and their Clients

Copy the Chapter02-SessionSamples directory and its contents into a directory of your choice. Run the NetBeans IDE and open the Chapter02-SessionSamples project using the File image Open Project menu. Make sure the Open Required Projects checkbox is checked.

9781430246923_Fig02-07.jpg

Figure 2-7.   Opening the Chapter02-SessionSamples project

Expand the Chapter02-SessionSamples-ejb node and observe that the three session beans that we created appear in the com.apress.ejb.chapter02 package. Similarly, the three client servlets appear under the Chapter02-SessionSamples-war node.

9781430246923_Fig02-08.jpg

Figure 2-8.   Verifying that Session Beans and their clients are available in the project

Invoke the context menu on Chapter02-SessionSamples node and build the application by selecting the Clean and Build menu option.

9781430246923_Fig02-09.jpg

Figure 2-9.   Building the application

Deploying the Session Beans and their Clients

Once you have compiled the session beans and the servlet clients, you can deploy the application to the GlassFish application server. Invoke the context menu on Chapter02-SessionSamples node and deploy the application by selecting the Deploy menu option.

9781430246923_Fig02-10.jpg

Figure 2-10.   Deploying the application

NetBeans will start the integrated GlassFish application server and deploy the application to the server. The server’s log window will log the deployment status of the application.

9781430246923_Fig02-11.jpg

Figure 2-11.   Log showing successful deployment

Running the Client Programs

Once the session beans and their client servlets are successfully deployed, we need to set the run target that we wish to execute. We have a choice of 3 run targets: ShopperCountClient, SearchFacadeClient, or ShoppingCartClient. To set the run target invoke the context menu on Chapter02-SessionSamples node and select the Properties menu option. Select the Run category and enter the run target in Relative URL text field and OK the dialog.

9781430246923_Fig02-12.jpg

Figure 2-12.   Setting a target to execute

To run the client servlets invoke the context menu on Chapter02-SessionSamples node and select the Run menu option.

9781430246923_Fig02-13.jpg

Figure 2-13.   Running the selected servlet

NetBeans will open your default browser and execute the selected servlet. Here is the output for the 3 client servlets.

9781430246923_Fig02-14.jpg

Figure 2-14.   Output of ShopperCountClient servlet

9781430246923_Fig02-15.jpg

Figure 2-15.   Output of SearchFacadeClient servlet

image Note   The application client container will be covered in detail in Chapter 12.

Conclusion

This chapter covered EJB session bean details using a specific set of examples. We looked at the simplified EJB model for developing session beans using standard Java language artifacts, such as Java classes and interfaces. We looked at session beans and some typical use cases in which session beans can be used for developing applications. We discussed three different types of session beans (stateless, stateful, and singleton), including the differences between them, and some general use cases for each. We covered session bean usage in 2-tier and 3-tier application architectures. We discussed the usage of dependency injection in stateless, stateful, and singleton beans. We considered ways to gain fine-grained control over application flow, including the use of lifecycle callback methods and interceptors in stateless and stateful beans, as well as the use of annotations like @PostConstruct and @PreDestroy. We looked at what is required to compile/build, package, and deploy session beans to the GlassFish application server. Finally, we looked at running the sample client programs using the GlassFish application client container.

In the next two chapters, we will drill down into the Java Persistence API (JPA) so that you can learn how to map POJOs to database tables and perform query and CRUD operations.

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

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