The Java EE 5 Tutorial

Part IV Enterprise Beans

Part Four explores Enterprise JavaBeans.

Chapter 20 Enterprise Beans

Enterprise beans are Java EE components that implement Enterprise JavaBeans (EJB) technology. Enterprise beans run in the EJB container, a runtime environment within the Application Server (see Container Types). Although transparent to the application developer, the EJB container provides system-level services such as transactions and security to its enterprise beans. These services enable you to quickly build and deploy enterprise beans, which form the core of transactional Java EE applications.

What Is an Enterprise Bean?

Written in the Java programming language, an enterprise bean is a server-side component that encapsulates the business logic of an application. The business logic is the code that fulfills the purpose of the application. In an inventory control application, for example, the enterprise beans might implement the business logic in methods called checkInventoryLevel and orderProduct. By invoking these methods, clients can access the inventory services provided by the application.

Benefits of Enterprise Beans

For several reasons, enterprise beans simplify the development of large, distributed applications. First, because the EJB container provides system-level services to enterprise beans, the bean developer can concentrate on solving business problems. The EJB container, rather than the bean developer, is responsible for system-level services such as transaction management and security authorization.

Second, because the beans rather than the clients contain the application’s business logic, the client developer can focus on the presentation of the client. The client developer does not have to code the routines that implement business rules or access databases. As a result, the clients are thinner, a benefit that is particularly important for clients that run on small devices.

Third, because enterprise beans are portable components, the application assembler can build new applications from existing beans. These applications can run on any compliant Java EE server provided that they use the standard APIs.

When to Use Enterprise Beans

You should consider using enterprise beans if your application has any of the following requirements:

Types of Enterprise Beans

Table 20–1 summarizes the two types of enterprise beans. The following sections discuss each type in more detail.

Table 20–1 Enterprise Bean Types

Enterprise Bean Type 

Purpose 

Session 

Performs a task for a client; optionally may implement a web service

Message-Driven 

Acts as a listener for a particular messaging type, such as the Java 

Message Service API 


Note –

Entity beans have been replaced by Java Persistence API entities. For information about entities, see Chapter 24, Introduction to the Java Persistence API.


What Is a Session Bean?

A session bean represents a single client inside the Application Server. To access an application that is deployed on the server, the client invokes the session bean’s methods. The session bean performs work for its client, shielding the client from complexity by executing business tasks inside the server.

As its name suggests, a session bean is similar to an interactive session. A session bean is not shared; it can have only one client, in the same way that an interactive session can have only one user. Like an interactive session, a session bean is not persistent. (That is, its data is not saved to a database.) When the client terminates, its session bean appears to terminate and is no longer associated with the client.

For code samples, see Chapter 22, Session Bean Examples.

State Management Modes

There are two types of session beans: stateful and stateless.

Stateful Session Beans

The state of an object consists of the values of its instance variables. In a stateful session bean, the instance variables represent the state of a unique client-bean session. Because the client interacts (“talks”) with its bean, this state is often called the conversational state.

The state is retained for the duration of the client-bean session. If the client removes the bean or terminates, the session ends and the state disappears. This transient nature of the state is not a problem, however, because when the conversation between the client and the bean ends there is no need to retain the state.

Stateless Session Beans

A stateless session bean does not maintain a conversational state with the client. When a client invokes the methods of a stateless bean, the bean’s instance variables may contain a state specific to that client, but only for the duration of the invocation. When the method is finished, the client-specific state should not be retained. Clients may, however, change the state of instance variables in pooled stateless beans, and this state is held over to the next invocation of the pooled stateless bean. Except during method invocation, all instances of a stateless bean are equivalent, allowing the EJB container to assign an instance to any client. That is, the state of a stateless session bean should apply accross all clients.

Because stateless session beans can support multiple clients, they can offer better scalability for applications that require large numbers of clients. Typically, an application requires fewer stateless session beans than stateful session beans to support the same number of clients.

A stateless session bean can implement a web service, but other types of enterprise beans cannot.

When to Use Session Beans

In general, you should use a session bean if the following circumstances hold:

Stateful session beans are appropriate if any of the following conditions are true:

To improve performance, you might choose a stateless session bean if it has any of these traits:

What Is a Message-Driven Bean?

A message-driven bean is an enterprise bean that allows Java EE applications to process messages asynchronously. It normally acts as a JMS message listener, which is similar to an event listener except that it receives JMS messages instead of events. The messages can be sent by any Java EE component (an application client, another enterprise bean, or a web component) or by a JMS application or system that does not use Java EE technology. Message-driven beans can process JMS messages or other kinds of messages.

For a simple code sample, see Chapter 23, A Message-Driven Bean Example. For more information about using message-driven beans, see Using the JMS API in a Java EE Application and Chapter 32, Java EE Examples Using the JMS API.

What Makes Message-Driven Beans Different from Session Beans?

The most visible difference between message-driven beans and session beans is that clients do not access message-driven beans through interfaces. Interfaces are described in the section Defining Client Access with Interfaces. Unlike a session bean, a message-driven bean has only a bean class.

In several respects, a message-driven bean resembles a stateless session bean.

The instance variables of the message-driven bean instance can contain some state across the handling of client messages (for example, a JMS API connection, an open database connection, or an object reference to an enterprise bean object).

Client components do not locate message-driven beans and invoke methods directly on them. Instead, a client accesses a message-driven bean through, for example, JMS by sending messages to the message destination for which the message-driven bean class is the MessageListener. You assign a message-driven bean’s destination during deployment by using Application Server resources.

Message-driven beans have the following characteristics:

When a message arrives, the container calls the message-driven bean’s onMessage method to process the message. The onMessage method normally casts the message to one of the five JMS message types and handles it in accordance with the application’s business logic. The onMessage method can call helper methods, or it can invoke a session bean to process the information in the message or to store it in a database.

A message can be delivered to a message-driven bean within a transaction context, so all operations within the onMessage method are part of a single transaction. If message processing is rolled back, the message will be redelivered. For more information, see Chapter 23, A Message-Driven Bean Example and Chapter 33, Transactions.

When to Use Message-Driven Beans

Session beans allow you to send JMS messages and to receive them synchronously, but not asynchronously. To avoid tying up server resources, do not to use blocking synchronous receives in a server-side component, and in general JMS messages should not be sent or received synchronously. To receive messages asynchronously, use a message-driven bean.

Defining Client Access with Interfaces

The material in this section applies only to session beans and not to message-driven beans. Because they have a different programming model, message-driven beans do not have interfaces that define client access.

A client can access a session bean only through the methods defined in the bean’s business interface. The business interface defines the client’s view of a bean. All other aspects of the bean (method implementations and deployment settings) are hidden from the client.

Well-designed interfaces simplify the development and maintenance of Java EE applications. Not only do clean interfaces shield the clients from any complexities in the EJB tier, but they also allow the beans to change internally without affecting the clients. For example, if you change a session bean from a stateless to a stateful session bean, you won’t have to alter the client code. But if you were to change the method definitions in the interfaces, then you might have to modify the client code as well. Therefore, it is important that you design the interfaces carefully to isolate your clients from possible changes in the beans.

Session beans can have more than one business interface. Session beans should, but are not required to, implement their business interface or interfaces.

When you design a Java EE application, one of the first decisions you make is the type of client access allowed by the enterprise beans: remote, local, or web service.

Remote Clients

A remote client of an enterprise bean has the following traits:

To create an enterprise bean that allows remote access, you must do one of the following:

The remote interface defines the business and life cycle methods that are specific to the bean. For example, the remote interface of a bean named BankAccountBean might have business methods named deposit and credit. Figure 20–1 shows how the interface controls the client’s view of an enterprise bean.

Figure 20–1 Interfaces for an Enterprise Bean with Remote Access

Diagram showing a remote client accessing an enterprise
bean's methods through its remote interface.

Local Clients

A local client has these characteristics:

The local business interface defines the bean’s business and life cycle methods. If the bean’s business interface is not decorated with @Local or @Remote, and the bean class does not specify the interface using @Local or @Remote, the business interface is by default a local interface. To build an enterprise bean that allows only local access, you may, but are not required to do one of the following:

Deciding on Remote or Local Access

Whether to allow local or remote access depends on the following factors.

If you aren’t sure which type of access an enterprise bean should have, choose remote access. This decision gives you more flexibility. In the future you can distribute your components to accommodate the growing demands on your application.

Although it is uncommon, it is possible for an enterprise bean to allow both remote and local access. If this is the case, either the business interface of the bean must be explicitly designated as a business interface by being decorated with the @Remote or @Local annotations, or the bean class must explicitly designate the business interfaces by using the @Remote and @Local annotations. The same business interface cannot be both a local and remote business interface.

Web Service Clients

A web service client can access a Java EE application in two ways. First, the client can access a web service created with JAX-WS. (For more information on JAX-WS, see Chapter 16, Building Web Services with JAX-WS.) Second, a web service client can invoke the business methods of a stateless session bean. Message beans cannot be accessed by web service clients.

Provided that it uses the correct protocols (SOAP, HTTP, WSDL), any web service client can access a stateless session bean, whether or not the client is written in the Java programming language. The client doesn’t even “know” what technology implements the service: stateless session bean, JAX-WS, or some other technology. In addition, enterprise beans and web components can be clients of web services. This flexibility enables you to integrate Java EE applications with web services.

A web service client accesses a stateless session bean through the bean’s web service endpoint implementation class. By default, all public methods in the bean class are accessible to web service clients. The @WebMethod annotation may be used to customize the behavior of web service methods. If the @WebMethod annotation is used to decorate the bean class’s methods, only those methods decorated with @WebMethod are exposed to web service clients.

For a code sample, see A Web Service Example: helloservice.

Method Parameters and Access

The type of access affects the parameters of the bean methods that are called by clients. The following topics apply not only to method parameters but also to method return values.

Isolation

The parameters of remote calls are more isolated than those of local calls. With remote calls, the client and bean operate on different copies of a parameter object. If the client changes the value of the object, the value of the copy in the bean does not change. This layer of isolation can help protect the bean if the client accidentally modifies the data.

In a local call, both the client and the bean can modify the same parameter object. In general, you should not rely on this side effect of local calls. Perhaps someday you will want to distribute your components, replacing the local calls with remote ones.

As with remote clients, web service clients operate on different copies of parameters than does the bean that implements the web service.

Granularity of Accessed Data

Because remote calls are likely to be slower than local calls, the parameters in remote methods should be relatively coarse-grained. A coarse-grained object contains more data than a fine-grained one, so fewer access calls are required. For the same reason, the parameters of the methods called by web service clients should also be coarse-grained.

The Contents of an Enterprise Bean

To develop an enterprise bean, you must provide the following files:

You package the files in the preceding list into an EJB JAR file, the module that stores the enterprise bean. An EJB JAR file is portable and can be used for different applications. To assemble a Java EE application, you package one or more modules (such as EJB JAR files) into an EAR file, the archive file that holds the application. When you deploy the EAR file that contains the bean’s EJB JAR file, you also deploy the enterprise bean to the Application Server. You can also deploy an EJB JAR that is not contained in an EAR file. Figure 20–2 shows the contents of an EJB JAR file.

Figure 20–2 Structure of an Enterprise Bean JAR

Diagram showing the structure and contents of an enterprise
bean JAR file.

Naming Conventions for Enterprise Beans

Because enterprise beans are composed of multiple parts, it’s useful to follow a naming convention for your applications. Table 20–2 summarizes the conventions for the example beans in this tutorial.

Table 20–2 Naming Conventions for Enterprise Beans

Item 

Syntax 

Example 

Enterprise bean name 

nameBean

AccountBean

Enterprise bean class 

nameBean

AccountBean

Business interface 

name

Account

The Life Cycles of Enterprise Beans

An enterprise bean goes through various stages during its lifetime, or life cycle. Each type of enterprise bean (stateful session, stateless session, or message-driven) has a different life cycle.

The descriptions that follow refer to methods that are explained along with the code examples in the next two chapters. If you are new to enterprise beans, you should skip this section and run the code examples first.

The Life Cycle of a Stateful Session Bean

Figure 20–3 illustrates the stages that a session bean passes through during its lifetime. The client initiates the life cycle by obtaining a reference to a stateful session bean. The container performs any dependency injection and then invokes the method annotated with @PostConstruct, if any. The bean is now ready to have its business methods invoked by the client.

Figure 20–3 Life Cycle of a Stateful Session Bean

Diagram showing the life cycle of a stateful session
bean.

While in the ready stage, the EJB container may decide to deactivate, or passivate, the bean by moving it from memory to secondary storage. (Typically, the EJB container uses a least-recently-used algorithm to select a bean for passivation.) The EJB container invokes the method annotated @PrePassivate, if any, immediately before passivating it. If a client invokes a business method on the bean while it is in the passive stage, the EJB container activates the bean, calls the method annotated @PostActivate, if any, and then moves it to the ready stage.

At the end of the life cycle, the client invokes a method annotated @Remove, and the EJB container calls the method annotated @PreDestroy, if any. The bean’s instance is then ready for garbage collection.

Your code controls the invocation of only one life-cycle method: the method annotated @Remove. All other methods in Figure 20–3 are invoked by the EJB container. See Chapter 34, Resource Connections for more information.

The Life Cycle of a Stateless Session Bean

Because a stateless session bean is never passivated, its life cycle has only two stages: nonexistent and ready for the invocation of business methods. Figure 20–4 illustrates the stages of a stateless session bean.

Figure 20–4 Life Cycle of a Stateless Session Bean

Diagram showing the life cycle of a stateless session
bean.

The client initiates the life cycle by obtaining a reference to a stateless session bean. The container performs any dependency injection and then invokes the method annotated @PostConstruct, if any. The bean is now ready to have its business methods invoked by the client.

At the end of the life cycle, the EJB container calls the method annotated @PreDestroy, if any. The bean’s instance is then ready for garbage collection.

The Life Cycle of a Message-Driven Bean

Figure 20–5 illustrates the stages in the life cycle of a message-driven bean.

Figure 20–5 Life Cycle of a Message-Driven Bean

Diagram showing the life cycle of a message-driven bean.

    The EJB container usually creates a pool of message-driven bean instances. For each instance, the EJB container performs these tasks:

  1. If the message-driven bean uses dependency injection, the container injects these references before instantiating the instance.

  2. The container calls the method annotated @PostConstruct, if any.

Like a stateless session bean, a message-driven bean is never passivated, and it has only two states: nonexistent and ready to receive messages.

At the end of the life cycle, the container calls the method annotated @PreDestroy, if any. The bean’s instance is then ready for garbage collection.

Further Information about Enterprise Beans

For more information on Enterprise JavaBeans technology, see:

Chapter 21 Getting Started with Enterprise Beans

This chapter shows how to develop, deploy, and run a simple Java EE application named converter. The purpose of converter is to calculate currency conversions between Japanese yen and Eurodollars. converter consists of an enterprise bean, which performs the calculations, and two types of clients: an application client and a web client.

    Here’s an overview of the steps you’ll follow in this chapter:

  1. Create the enterprise bean: ConverterBean.

  2. Create the application client: ConverterClient.

  3. Create the web client in converter-war.

  4. Deploy converter onto the server.

  5. Run the application client.

  6. Using a browser, run the web client.

Before proceeding, make sure that you’ve done the following:

Creating the Enterprise Bean

The enterprise bean in our example is a stateless session bean called ConverterBean. The source code for ConverterBean is in the tut-install/javaeetutorial5/examples/ejb/converter/converter-ejb/src/java/ directory.

    Creating ConverterBean requires these steps:

  1. Coding the bean’s business interface and class (the source code is provided)

  2. Compiling the source code with the Ant tool

Coding the Enterprise Bean

The enterprise bean in this example needs the following code:

Coding the Business Interface

The business interface defines the business methods that a client can call. The business methods are implemented in the enterprise bean class. The source code for the Converter remote business interface follows.

package com.sun.tutorial.javaee.ejb;

import java.math.BigDecimal;
import javax.ejb.Remote;

@Remote
public interface Converter {
    public BigDecimal dollarToYen(BigDecimal dollars);
    public BigDecimal yenToEuro(BigDecimal yen);
}

Note the @Remote annotation decorating the interface definition. This lets the container know that ConverterBean will be accessed by remote clients.

Coding the Enterprise Bean Class

The enterprise bean class for this example is called ConverterBean. This class implements the two business methods (dollarToYen and yenToEuro) that the Converter remote business interface defines. The source code for the ConverterBean class follows.

package com.sun.tutorial.javaee.ejb;

import java.math.BigDecimal;
import javax.ejb.*;

@Stateless
public class ConverterBean implements Converter {
    private BigDecimal yenRate = new BigDecimal("115.3100");
    private BigDecimal euroRate = new BigDecimal("0.0071");

    public BigDecimal dollarToYen(BigDecimal dollars) {
        BigDecimal result = dollars.multiply(yenRate);
        return result.setScale(2, BigDecimal.ROUND_UP);
    }

    public BigDecimal yenToEuro(BigDecimal yen) {
        BigDecimal result = yen.multiply(euroRate);
        return result.setScale(2, BigDecimal.ROUND_UP);
    }
}

Note the @Stateless annotation decorating the enterprise bean class. This lets the container know that ConverterBean is a stateless session bean.

Compiling and Packaging the converter Example

Now you are ready to compile the remote business interface (Converter.java) and the enterprise bean class (ConverterBean.java), and package the compiled classes into an enterprise bean JAR.

Compiling and Packaging the converter Example in NetBeans IDE

    Follow these instructions to build and package the converter example in NetBeans IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the converter folder.

  4. Select the Open as Main Project and Open Required Projects check boxes.

  5. Click Open Project.

  6. In the Projects tab, right-click the converter project and select Build. You will see the output in the Output tab.

Compiling and Packaging the converter Example Using Ant

    To compile and package converter using Ant, do the following:

  1. In a terminal window, go to this directory:


    tut-install/javaeetutorial5/examples/ejb/converter/
  2. Type the following command:


    ant
    

This command calls the default task, which compiles the source files for the enterprise bean and the application client, placing the class files in the build subdirectories (not the src directory) of each submodule. Then the default task packages each submodule into the appropriate package file: converter-app-client.jar for the application client, converter-ejb.jar for the enterprise bean JAR, and converter-war.war for the web client. The web client in this example requires no compilation. For more information about the Ant tool, see Building the Examples.


Note –

When compiling the code, the preceding ant task includes the javaee.jar file in the classpath. This file resides in the lib directory of your Application Server installation. If you plan to use other tools to compile the source code for Java EE components, make sure that the classpath includes the javaee.jar file.


Creating the converter Application Client

An application client is a program written in the Java programming language. At runtime, the client program executes in a different virtual machine than the Application Server. For detailed information on the appclient command-line tool, see the man page at appclient(1M).

The application client in this example requires two JAR files. The first JAR file is for the Java EE component of the client. This JAR file contains the client’s deployment descriptor and class files; it is created when you run the New Application Client wizard. Defined by the Java EE Specification, this JAR file is portable across all compliant application servers.

The second JAR file contains all the classes that are required by the client program at runtime. These classes enable the client to access the enterprise beans that are running in the Application Server. The JAR file is retrieved before you run the application. Because this retrieved JAR file is not covered by the Java EE specification, it is implementation-specific, intended only for the Application Server.

The application client source code is in the ConverterClient.java file, which is in this directory:


tut-install/javaeetutorial5/examples/ejb/converter/converter-app-client/src/java/

You compiled this code along with the enterprise bean code in the section Compiling and Packaging the converter Example.

Coding the converter Application Client

The ConverterClient.java source code illustrates the basic tasks performed by the client of an enterprise bean:

Creating a Reference to an Enterprise Bean Instance

Java EE application clients refer to enterprise bean instances by annotating static fields with the @EJB annotation. The annotated static field represents the enterprise bean’s business interface, which will resolve to the session bean instance when the application client container injects the resource references at runtime.

@EJB
private static Converter converter;

The field is static because the client class runs in a static context.

Invoking a Business Method

Calling a business method is easy: you simply invoke the method on the injected Converter object. The EJB container will invoke the corresponding method on the ConverterBean instance that is running on the server. The client invokes the dollarToYen business method in the following lines of code.

BigDecimal param = new BigDecimal ("100.00");
BigDecimal amount = currencyConverter.dollarToYen(param);

ConverterClient Source Code

The full source code for the ConverterClient program follows.

package com.sun.tutorial.javaee.ejb;

import java.math.BigDecimal;
import javax.ejb.EJB;

public class ConverterClient {
    @EJB
    private static Converter converter;
    
    public ConverterClient(String[] args) {
    }

    public static void main(String[] args) {
        ConverterClient client = new ConverterClient(args);
        client.doConversion();
    }

    public void doConversion() {
        try {
            BigDecimal param = new BigDecimal("100.00");
            BigDecimal yenAmount = converter.dollarToYen(param);

            System.out.println("$" + param + " is " + yenAmount
                    + " Yen.");
            BigDecimal euroAmount = converter.yenToEuro(yenAmount);
            System.out.println(yenAmount + " Yen is " + euroAmount
                    + " Euro.");

            System.exit(0);
        } catch (Exception ex) {
            System.err.println("Caught an unexpected exception!");
            ex.printStackTrace();
        }
    }
}

Compiling the converter Application Client

The application client files are compiled at the same time as the enterprise bean files, as described in Compiling and Packaging the converter Example.

Creating the converter Web Client

The web client is contained in the JSP page tut-install/javaeetutorial5/examples/ejb/converter/converter-war/web/index.jsp. A JSP page is a text-based document that contains JSP elements, which construct dynamic content, and static template data, which can be expressed in any text-based format such as HTML, WML, and XML.

Coding the converter Web Client

The statements (in bold in the following code) for locating the business interface, creating an enterprise bean instance, and invoking a business method are nearly identical to those of the application client. The parameter of the lookup method is the only difference.

The classes needed by the client are declared using a JSP page directive (enclosed within the <%@ %> characters). Because locating the business interface and creating the enterprise bean are performed only once, this code appears in a JSP declaration (enclosed within the <%! %> characters) that contains the initialization method, jspInit, of the JSP page. The declaration is followed by standard HTML markup for creating a form that contains an input field. A scriptlet (enclosed within the <% %> characters) retrieves a parameter from the request and converts it to a BigDecimal object. Finally, a JSP scriptlet invokes the enterprise bean’s business methods, and JSP expressions (enclosed within the <%= %> characters) insert the results into the stream of data returned to the client.

<%@ page import="converter.ejb.Converter,
            java.math.*, javax.naming.*"%>

 <%!
    private Converter converter = null;
    public void jspInit() {
        try {
            InitialContext ic = new InitialContext();
            converter = (Converter)
                    ic.lookup(Converter.class.getName());
        } catch (Exception ex) {
            System.out.println("Couldn’t create converter bean."+
                    ex.getMessage());
        }
    }

    public void jspDestroy() {
        converter = null;
    }
%>
<html>
    <head>
        <title>Converter</title>
    </head>

    <body bgcolor="white">
        <h1>Converter</h1>
        <hr>
        <p>Enter an amount to convert:</p>
        <form method="get">
            <input type="text" name="amount" size="25">
            <br>
            <p>
            <input type="submit" value="Submit">
            <input type="reset" value="Reset">
        </form>

        <%
            String amount = request.getParameter("amount");
            if ( amount != null && amount.length() > 0 ) {
                BigDecimal d = new BigDecimal(amount);

                BigDecimal yenAmount = converter.dollarToYen(d);
        %>
        <p>
        <%= amount %> dollars are  <%= yenAmount %>  Yen.
        <p>
        <%
                BigDecimal euroAmount =
                        converter.yenToEuro(yenAmount);
        %>
        <%= amount %> Yen are <%= euroAmount %>  Euro.
        <%
            }
        %>
    </body>
</html>

Compiling the converter Web Client

The Application Server automatically compiles web clients that are JSP pages. If the web client were a servlet, you would have to compile it.

Deploying the converter Java EE Application

Now that the Java EE application contains the components, it is ready for deployment. You can deploy the application using either NetBeans IDE or Ant.

Deploying the converter Example Using NetBeans IDE

    Follow these instructions to deploy the converter example to your Application Server instance using NetBeans IDE.

  1. In NetBeans IDE, make sure the converter application is open.

  2. In the Projects tab, right-click the converter project and select Undeploy and Deploy. You will see the output in the Output tab.

Deploying the converter Example Using Ant

To deploy converter.ear using Ant, run the deploy task.


ant deploy

converter.ear will be deployed to the Application Server.

Running the converter Application Client

When you run the application client, the application client container first injects the resources specified in the client and then runs the client. You can run the application client using either NetBeans IDE or Ant.

Running the converter Application Client Using NetBeans IDE

    Follow these instructions to run the application client using NetBeans IDE.

  1. In NetBeans IDE, make sure the converter application is open.

  2. In the Projects tab, right-click the converter project and select Run. You will see the following output in the Output tab:


    ...
    $100.00 is 11258.00 Yen.
    11258.00 Yen is 78.81 Euro.
    ...

Running the converter Application Client Using Ant

    To run the application client using Ant, perform the following steps.

  1. In a terminal window, go to this directory:


    tut-install/javaeetutorial5/examples/ejb/converter/
  2. Type the following command:


    ant run
    

    This task will retrieve the application client JAR, converterClient.jar and run the retrieved client JAR. converterClient.jar contains the application client class and the support classes needed to access ConverterBean. Although you are using Ant to run the client, this task is the equivalent of running:


    appclient -client client-jar/converterClient.jar
    
  3. In the terminal window, the client displays these lines:


    ...
    $100.00 is 11531.00 Yen.
    11531.00 Yen is 81.88 Euro.
    ...

Running the converter Web Client

To run the web client, point your browser at the following URL. Replace host with the name of the host running the Application Server. If your browser is running on the same host as the Application Server, you can replace host with localhost.


http://host:8080/converter

After entering 100 in the input field and clicking Submit, you should see the screen shown in Figure 21–1.

Figure 21–1 converter Web Client

Screenshot showing the converter web client.

Modifying the Java EE Application

The Application Server supports iterative development. Whenever you make a change to a Java EE application, you must redeploy the application.

Modifying a Class File

    To modify a class file in an enterprise bean, you change the source code, recompile it, and redeploy the application. For example, if you want to change the exchange rate in the dollarToYen business method of the ConverterBean class, you would follow these steps.

  1. Edit ConverterBean.java.

  2. Recompile ConverterBean.java.

    1. In a terminal window, go to the tut-install/javaeetutorial5/examples/ejb/converter/ subdirectory.

    2. Type the following command:


      ant
      

      This command runs the default task, which repackages the entire application (application client, enterprise bean JAR, and web client).

  3. Type the following command:


    ant deploy
    

To modify the contents of a WAR file, or to modify the application client, follow the preceding steps.

Chapter 22 Session Bean Examples

Session beans provide a simple but powerful way to encapsulate business logic within an application. They can be accessed from remote Java clients, web service clients, and from components running in the same server.

In Chapter 21, Getting Started with Enterprise Beans, you built a stateless session bean named ConverterBean. This chapter examines the source code of three more session beans:

The cart Example

The cart session bean represents a shopping cart in an online bookstore. The bean’s client can add a book to the cart, remove a book, or retrieve the cart’s contents. To assemble cart, you need the following code:

All session beans require a session bean class. All enterprise beans that permit remote access must have a remote business interface. To meet the needs of a specific application, an enterprise bean may also need some helper classes. The CartBean session bean uses two helper classes (BookException and IdVerifier) which are discussed in the section Helper Classes.

The source code for this example is in the tut-install/javaeetutorial5/examples/ejb/cart/ directory.

The Business Interface

The Cart business interface is a plain Java interface that defines all the business methods implemented in the bean class. If the bean class implements a single interface, that interface is assumed to the business interface. The business interface is a local interface unless it is annotated with the javax.ejb.Remote annotation; the javax.ejb.Local annotation is optional in this case.

The bean class may implement more than one interface. If the bean class implements more than one interface, either the business interfaces must be explicitly annotated either @Local or @Remote, or the business interfaces must be specified by decorating the bean class with @Local or @Remote. However, the following interfaces are excluded when determining if the bean class implements more than one interface:

The source code for the Cart business interface follows:

package com.sun.tutorial.javaee.ejb;

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

@Remote
public interface Cart {
    public void initialize(String person) throws BookException;
    public void initialize(String person, String id)
         throws BookException;
    public void addBook(String title);
    public void removeBook(String title) throws BookException;
    public List<String> getContents();
    public void remove();
}

Session Bean Class

The session bean class for this example is called CartBean. Like any stateful session bean, the CartBean class must meet these requirements:

Stateful session beans also may:

The source code for the CartBean class follows.

package com.sun.tutorial.javaee.ejb;

import java.util.ArrayList;
import java.util.List;
import javax.ejb.Remove;
import javax.ejb.Stateful;

@Stateful
public class CartBean implements Cart {
    String customerName;
    String customerId;
    List<String> contents;

    public void initialize(String person) throws BookException {
        if (person == null) {
            throw new BookException("Null person not allowed.");
        } else {
            customerName = person;
        }

        customerId = "0";
        contents = new ArrayList<String>();
    }

    public void initialize(String person, String id)
                 throws BookException {
        if (person == null) {
            throw new BookException("Null person not allowed.");
        } else {

            customerName = person;
        }

        IdVerifier idChecker = new IdVerifier();

        if (idChecker.validate(id)) {
            customerId = id;
        } else {
            throw new BookException("Invalid id: " + id);
        }

        contents = new ArrayList<String>();
    }

    public void addBook(String title) {
        contents.add(title);
    }

    public void removeBook(String title) throws BookException {
        boolean result = contents.remove(title);
        if (result == false) {
            throw new BookException(title + " not in cart.");
        }
    }

    public List<String> getContents() {
        return contents;
    }

    @Remove
    public void remove() {
        contents = null;
    }
}

Life-Cycle Callback Methods

Methods in the bean class may be declared as a life-cycle callback method by annotating the method with the following annotations:

Life-cycle callback methods must return void and have no parameters.

@PostConstruct methods are invoked by the container on newly constructed bean instances after all dependency injection has completed and before the first business method is invoked on the enterprise bean.

@PreDestroy methods are invoked after any method annotated @Remove has completed, and before the container removes the enterprise bean instance.

@PostActivate methods are invoked by the container after the container moves the bean from secondary storage to active status.

@PrePassivate methods are invoked by the container before the container passivates the enterprise bean, meaning the container temporarily removes the bean from the environment and saves it to secondary storage.

Business Methods

The primary purpose of a session bean is to run business tasks for the client. The client invokes business methods on the object reference it gets from dependency injection or JNDI lookup. From the client’s perspective, the business methods appear to run locally, but they actually run remotely in the session bean. The following code snippet shows how the CartClient program invokes the business methods:

cart.create("Duke DeEarl", "123");
...
cart.addBook("Bel Canto");
 ...
List<String> bookList = cart.getContents();
...
cart.removeBook("Gravity’s Rainbow");

The CartBean class implements the business methods in the following code:

public void addBook(String title) {
   contents.addElement(title);
}

public void removeBook(String title) throws BookException {
   boolean result = contents.remove(title);
   if (result == false) {
      throw new BookException(title + "not in cart.");
   }
}

public List<String> getContents() {
   return contents;
}

The signature of a business method must conform to these rules:

The throws clause can include exceptions that you define for your application. The removeBook method, for example, throws the BookException if the book is not in the cart.

To indicate a system-level problem, such as the inability to connect to a database, a business method should throw a javax.ejb.EJBException. The container will not wrap application exceptions such as BookException. Because EJBException is a subclass of RuntimeException, you do not need to include it in the throws clause of the business method.

The Remove Method

Business methods annotated with javax.ejb.Remove in the stateful session bean class can be invoked by enterprise bean clients to remove the bean instance. The container will remove the enterprise bean after a @Remove method completes, either normally or abnormally.

In CartBean, the remove method is a @Remove method:

@Remove
public void remove() {
	contents = null;
}

Helper Classes

The CartBean session bean has two helper classes: BookException and IdVerifier. The BookException is thrown by the removeBook method, and the IdVerifier validates the customerId in one of the create methods. Helper classes may reside in the EJB JAR file that contains the enterprise bean class, or in an EAR that contains the EJB JAR.

Building, Packaging, Deploying, and Running the cart Example

You can build, package, deploy, and run the cart application using either NetBeans IDE or the Ant tool.

Building, Packaging, and Deploying the cart Example Using NetBeans IDE

    Follow these instructions to build, package, and deploy the cart example to your Application Server instance using the NetBeans IDE IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the cart folder.

  4. Select the Open as Main Project and Open Required Projects check boxes.

  5. Click Open Project.

  6. In the Projects tab, right-click the cart project and select Undeploy and Deploy.

This builds and packages the application into cart.ear, located in tut-install/javaeetutorial5/examples/ejb/cart/dist/, and deploys this EAR file to your Application Server instance.

Running the cart Application Client Using NetBeans IDE

To run cart’s application client, select Run->Run Main Project. You will see the output of the application client in the Output pane:

...
Retrieving book title from cart: Infinite Jest
Retrieving book title from cart: Bel Canto
Retrieving book title from cart: Kafka on the Shore
Removing "Gravity’s Rainbow" from cart.
Caught a BookException: "Gravity’s Rainbow" not in cart.
Java Result: 1
run-cart-app-client:
run-nb:
BUILD SUCCESSFUL (total time: 14 seconds)

Building, Packaging, and Deploying the cart Example Using Ant

    Now you are ready to compile the remote interface (Cart.java), the home interface (CartHome.java), the enterprise bean class (CartBean.java), the client class (CartClient.java), and the helper classes (BookException.java and IdVerifier.java).

  1. In a terminal window, go to this directory:


    tut-install/javaeetutorial5/examples/ejb/cart/
  2. Type the following command:


    ant
    

    This command calls the default target, which builds and packages the application into an EAR file, cart.ear, located in the dist directory.

  3. Type the following command:


    ant deploy
    

    cart.ear will be deployed to the Application Server.

Running the cart Application Client Using Ant

    When you run the client, the application client container injects any component references declared in the application client class, in this case the reference to the Cart enterprise bean. To run the application client, perform the following steps.

  1. In a terminal window, go to this directory:


    tut-install/javaeetutorial5/examples/ejb/cart/
  2. Type the following command:


    ant run
    

    This task will retrieve the application client JAR, cartClient.jar and run the application client. cartClient.jar contains the application client class, the helper class BookException, and the Cart business interface.

    This is the equivalent of running:


    appclient -client cartClient.jar
    
  3. In the terminal window, the client displays these lines:


    [echo] running application client container.
    [exec] Retrieving book title from cart: Infinite Jest
    [exec] Retrieving book title from cart: Bel Canto
    [exec] Retrieving book title from cart: Kafka on the Shore
    [exec] Removing "Gravity’s Rainbow" from cart.
    [exec] Caught a BookException: "Gravity’s Rainbow" not in cart.
    [exec] Result: 1

The all Task

As a convenience, the all task will build, package, deploy, and run the application. To do this, enter the following command:


ant all

Undeploying the cart Example

    To undeploy cart.ear using NetBeans IDE:

  1. Click the Services tab.

  2. Expand the Servers node and locate the Application Server instance to which you deployed cart.

  3. Expand your Application Server instance node, then Applications->Enterprise Applications.

  4. Right-click cart and select Undeploy.

To undeploy cart.ear using Ant, enter the following command:


ant undeploy

A Web Service Example: helloservice

This example demonstrates a simple web service that generates a response based on information received from the client. HelloServiceBean is a stateless session bean that implements a single method, sayHello. This method matches the sayHello method invoked by the client described in A Simple JAX-WS Client.

The Web Service Endpoint Implementation Class

HelloServiceBean is the endpoint implementation class. The endpoint implementation class is typically the primary programming artifact for enterprise bean web service endpoints. The web service endpoint implementation class has the following requirements:

Stateless Session Bean Implementation Class

The HelloServiceBean class implements the sayHello method, which is annotated @WebMethod. The source code for the HelloServiceBean class follows:

package com.sun.tutorial.javaee.ejb;

import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;

@Stateless
@WebService
public class HelloServiceBean {
    private String message = "Hello, ";

    public void HelloServiceBean() {}

    @WebMethod
    public String sayHello(String name) {
        return message + name + ".";
    }
}

Building, Packaging, Deploying, and Testing the helloservice Example

You can build, package, and deploy the helloservice example using either NetBeans IDE or Ant. You can then use the Admin Console to test the web service endpoint methods.

Building, Packaging, and Deploying the helloservice Example Using NetBeans IDE

    Follow these instructions to build, package, and deploy the helloservice example to your Application Server instance using the NetBeans IDE IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the helloservice folder.

  4. Select the Open as Main Project and Open Required Projects check boxes.

  5. Click Open Project.

  6. In the Projects tab, right-click the helloservice project and select Undeploy and Deploy.

This builds and packages to application into helloservice.ear, located in tut-install/javaeetutorial5/examples/ejb/helloservice/dist, and deploys this ear file to your Application Server instance.

Building, Packaging, and Deploying the helloservice Example Using Ant

    Follow these instructions to build, package, and deploy the helloservice example to your Application Server instance using Ant.

  1. In a terminal window, go to the tut-install/javaeetutorial5/examples/ejb/helloservice/ directory.

  2. To build helloservice, type the following command:


    ant
    

    This runs the default task, which compiles the source files and packages the application into a JAR file located at tut-install/examples/ejb/helloservice/dist/helloservice.jar.

  3. To deploy helloservice, type the following command:


    ant deploy
    

    Upon deployment, the Application Server generates additional artifacts required for web service invocation, including the WSDL file.

Testing the Service without a Client

  1. The Application Server Admin Console allows you to test the methods of a web service endpoint. To test the sayHello method of HelloServiceBean, do the following:Open the Admin Console by opening the following URL in a web browser:


    http://localhost:4848/
  2. Enter the admin username and password to log in to the Admin Console.

  3. Click Web Services in the left pane of the Admin Console.

  4. Click helloservice.

  5. Click Test.

  6. Under Methods, enter a name as the parameter to the sayHello method.

  7. Click the sayHello button.

    This will take you to the sayHello Method invocation page.

  8. Under Method returned, you’ll see the response from the endpoint.

Using the Timer Service

Applications that model business work flows often rely on timed notifications. The timer service of the enterprise bean container enables you to schedule timed notifications for all types of enterprise beans except for stateful session beans. You can schedule a timed notification to occur at a specific time, after a duration of time, or at timed intervals. For example, you could set timers to go off at 10:30 AM on May 23, in 30 days, or every 12 hours.

When a timer expires (goes off), the container calls the method annotated @Timeout in the bean’s implementation class. The @Timeout method contains the business logic that handles the timed event.

The Timeout Method

Methods annotated @Timeout in the enterprise bean class must return void and take a javax.ejb.Timer object as the only parameter. They may not throw application exceptions.

@Timeout
public void timeout(Timer timer) {
    System.out.println("TimerBean: timeout occurred");
}

Creating Timers

To create a timer, the bean invokes one of the createTimer methods of the TimerService interface. (For details on the method signatures, see the TimerService API documentation at http://java.sun.com/javaee/5/docs/api/javax/ejb/TimerService.html.) When the bean invokes createTimer, the timer service begins to count down the timer duration.

The bean described in The timersession Example creates a timer as follows:

Timer timer = timerService.createTimer(intervalDuration,
        "Created new timer");

In the timersession example, createTimer is invoked in a business method, which is called by a client.

Timers are persistent. If the server is shut down (or even crashes), timers are saved and will become active again when the server is restarted. If a timer expires while the server is down, the container will call the @Timeout method when the server is restarted.

The Date and long parameters of the createTimer methods represent time with the resolution of milliseconds. However, because the timer service is not intended for real-time applications, a callback to the @Timeout method might not occur with millisecond precision. The timer service is for business applications, which typically measure time in hours, days, or longer durations.

Canceling and Saving Timers

Timers can be canceled by the following events:

If a method is invoked on a canceled timer, the container throws the javax.ejb.NoSuchObjectLocalException.

To save a Timer object for future reference, invoke its getHandle method and store the TimerHandle object in a database. (A TimerHandle object is serializable.) To re-instantiate the Timer object, retrieve the handle from the database and invoke getTimer on the handle. A TimerHandle object cannot be passed as an argument of a method defined in a remote or web service interface. In other words, remote clients and web service clients cannot access a bean’s TimerHandle object. Local clients, however, do not have this restriction.

Getting Timer Information

In addition to defining the cancel and getHandle methods, the Timer interface defines methods for obtaining information about timers:

public long getTimeRemaining();
public java.util.Date getNextTimeout();
public java.io.Serializable getInfo();

The getInfo method returns the object that was the last parameter of the createTimer invocation. For example, in the createTimer code snippet of the preceding section, this information parameter is a String object with the value created timer.

To retrieve all of a bean’s active timers, call the getTimers method of the TimerService interface. The getTimers method returns a collection of Timer objects.

Transactions and Timers

An enterprise bean usually creates a timer within a transaction. If this transaction is rolled back, the timer creation is also rolled back. Similarly, if a bean cancels a timer within a transaction that gets rolled back, the timer cancellation is rolled back. In this case, the timer’s duration is reset as if the cancellation had never occurred.

In beans that use container-managed transactions, the @Timeout method usually has the Required or RequiresNew transaction attribute to preserve transaction integrity. With these attributes, the EJB container begins the new transaction before calling the @Timeout method. If the transaction is rolled back, the container will call the @Timeout method at least one more time.

The timersession Example

The source code for this example is in the tut-install/javaeetutorial5/examples/ejb/timersession/timersession-ejb/src/java/ directory.

TimerSessionBean is a stateless session bean that shows how to set a timer. In the source code listing of TimerSessionBean that follows, note the createTimer and @Timeout methods. Because it’s a business method, createTimer is defined in the bean’s remote business interface (TimerSession) and can be invoked by the client. In this example, the client invokes createTimer with an interval duration of 30,000 milliseconds. The createTimer method creates a new timer by invoking the createTimer method of TimerService. A TimerService instance is injected by the container when the bean is created. Now that the timer is set, the EJB container will invoke the timeout method of TimerSessionBean when the timer expires, in about 30 seconds. Here’s the source code for the TimerSessionBean class:

package com.sun.tutorial.javaee.ejb;

import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
@Stateless
public class TimerSessionBean implements TimerSession {
    @Resource
    TimerService timerService;

private static final Logger logger = Logger
        .getLogger("com.sun.tutorial.javaee.ejb.
                timersession.TimerSessionBean");

    public void createTimer(long intervalDuration) {
        Timer timer = timerService.createTimer(intervalDuration,
                "Created new timer");
    }

    @Timeout
    public void timeout(Timer timer) {
        logger.info("Timeout occurred");
    }
}

Note –

Application Server has a default minimum timeout value of 7000 milliseconds, or 7 seconds. If you need to set the timeout value lower than 7000 milliseconds, change the value of the minimum-delivery-interval-in-millis element in domain-dir/config/domain.xml. Due to virtual machine constraints, the lowest practical value for minimum-delivery-interval-in-millis is around 10 milliseconds.


Building, Packaging, Deploying, and Running the timersession Example

You can build, package, deploy, and run the timersession example using either NetBeans IDE or Ant.

Building, Packaging, Deploying, and Running the timersession Example Using NetBeans IDE

    Follow these instructions to build, package, and deploy the timersession example to your Application Server instance using the NetBeans IDE IDE.

  1. In NetBeans IDE, select File->Open Project.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the timersession folder.

  4. Select the Open as Main Project and Open Required Projects check boxes.

  5. Click Open Project.

  6. Select Run->Run Main Project.

This builds and packages the application into timersession.ear, located in tut-install/javaeetutorial5/examples/ejb/timersession/dist/, deploys this EAR file to your Application Server instance, and then runs the application client.

You will see the output from the application client in the Output tab:


...
Creating a timer with an interval duration of 3000 ms.
run-timersession-app-client:
run-nb:
BUILD SUCCESSFUL (total time: 16 seconds)

    The output from the timer is sent to the server.log file located in the domain-dir/server/logs/ directory. To view this file:

  1. Click the Services tab.

  2. Right-click your Application Server instance and select View Server Log.

Look for the following line at the bottom of server.log:


Timeout occurred

Building, Packaging, and Deploying the timersession Example Using Ant

    Follow these instructions to build, package, and deploy the timersession example to your Application Server instance using Ant.

  1. In a terminal window, go to the tut-install/javaeetutorial5/examples/ejb/timersession/ directory.

  2. To build TimerSessionBean, type the following command:


    ant build
    

    This runs the default task, which compiles the source files and packages the application into an EAR file located at tut-install/examples/ejb/timersession/dist/timersession.ear.

  3. To deploy the application, type the following command:


    ant deploy
    

Running the timersession Application Client Using Ant

    To run the application client, perform the following steps.

  1. In a terminal window, go to the tut-install/javaeetutorial5/examples/ejb/timersession/ directory.

  2. Type the following command:


    ant run
    

    This task first retrieves the client JAR, timersessionClient.jar to the dist directory, and then runs the client. This is the equivalent of running:


    appclient -client TimerSessionAppClient.jar
    
  3. In the terminal window, the client displays these lines:


    Creating a timer with an interval duration of 30000 ms.

The output from the timer is sent to the server.log file located in the domain-dir/server/logs/ directory.

    View the output in the Admin Console:

  1. Open the Admin Console by opening the following URL in a web browser:


    http://localhost:4848/
  2. Enter the admin username and password to log in to the Admin Console.

  3. Click Application Server in the navigation pane.

  4. Click View Log Files.

  5. At the top of the page, you’ll see this line in the Message column:


    Timeout occurred

Alternatively, you can look at the log file directly. After about 30 seconds, open server.log in a text editor and you will see the following lines:


TimerSessionBean: Timeout occurred

Handling Exceptions

The exceptions thrown by enterprise beans fall into two categories: system and application.

A system exception indicates a problem with the services that support an application. Examples of these problems include the following: a connection to an external resource cannot be obtained or an injected resource cannot be found. If your enterprise bean encounters a system-level problem, it should throw a javax.ejb.EJBException. Because the EJBException is a subclass of the RuntimeException, you do not have to specify it in the throws clause of the method declaration. If a system exception is thrown, the EJB container might destroy the bean instance. Therefore, a system exception cannot be handled by the bean’s client program; it requires intervention by a system administrator.

An application exception signals an error in the business logic of an enterprise bean. Application exceptions are typically exceptions that you’ve coded yourself, such as the BookException thrown by the business methods of the CartBean example. When an enterprise bean throws an application exception, the container does not wrap it in another exception. The client should be able to handle any application exception it receives.

If a system exception occurs within a transaction, the EJB container rolls back the transaction. However, if an application exception is thrown within a transaction, the container does not roll back the transaction.

Chapter 23 A Message-Driven Bean Example

Message-driven beans can implement any messaging type. Most commonly, they implement the Java Message Service (JMS) technology. The example in this chapter uses JMS technology, so you should be familiar with basic JMS concepts such as queues and messages. To learn about these concepts, see Chapter 31, The Java Message Service API.

This chapter describes the source code of a simple message-driven bean example. Before proceeding, you should read the basic conceptual information in the section What Is a Message-Driven Bean? as well as Using Message-Driven Beans to Receive Messages Asynchronously in Chapter 31, The Java Message Service API.

simplemessage Example Application Overview

The simplemessage application has the following components:

Figure 23–1 illustrates the structure of this application. The application client sends messages to the queue, which was created administratively using the Admin Console. The JMS provider (in this case, the Application Server) delivers the messages to the instances of the message-driven bean, which then processes the messages.

Figure 23–1 The simplemessage Application

Diagram of application showing an application client
sending a message to a queue, and the message being delivered to a message-driven
bean

The source code for this application is in the tut-install/javaeetutorial5/examples/ejb/simplemessage/ directory.

The simplemessage Application Client

The SimpleMessageClient sends messages to the queue that the SimpleMessageBean listens to. The client starts by injecting the the connection factory and queue resources:

@Resource(mappedName="jms/ConnectionFactory")
private static ConnectionFactory connectionFactory;

@Resource(mappedName=”jms/Queue”)
private static Queue queue;

Next, the client creates the connection, session, and message producer:

connection = connectionFactory.createConnection();
session = connection.createSession(false,
    Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(queue);

Finally, the client sends several messages to the queue:

message = session.createTextMessage();

for (int i = 0; i < NUM_MSGS; i++) {
    message.setText("This is message " + (i + 1));
    System.out.println("Sending message: " +
        message.getText());
    messageProducer.send(message);
}

The Message-Driven Bean Class

The code for the SimpleMessageBean class illustrates the requirements of a message-driven bean class:

It is recommended, but not required, that a message-driven bean class implement the message listener interface for the message type it supports. A bean that supports the JMS API implements the javax.jms.MessageListener interface.

Unlike session beans and entities, message-driven beans do not have the remote or local interfaces that define client access. Client components do not locate message-driven beans and invoke methods on them. Although message-driven beans do not have business methods, they may contain helper methods that are invoked internally by the onMessage method.

For the Application Server, the @MessageDriven annotation typically contains a mappedName element that specifies the JNDI name of the destination from which the bean will consume messages. For complex message-driven beans there can also be an activationconfig element containing @ActivationConfigProperty annotations used by the bean. See A Java EE Application That Uses the JMS API with a Session Bean for an example.

A message-driven bean can also inject a MessageDrivenContext resource. Commonly you use this resource to call the setRollbackOnly method to handle exceptions for a bean that uses container-managed transactions.

Therefore, the first few lines of the SimpleMessageBean class look like this:

@MessageDriven(mappedName="jms/Queue")
public class SimpleMessageBean implements MessageListener {
    @Resource
    private MessageDrivenContext mdc;
    ...

The onMessage Method

When the queue receives a message, the EJB container invokes the message listener method or methods. For a bean that uses JMS, this is the onMessage method of the MessageListener interface.

A message listener method must follow these rules:

The onMessage method is called by the bean’s container when a message has arrived for the bean to service. This method contains the business logic that handles the processing of the message. It is the message-driven bean’s responsibility to parse the message and perform the necessary business logic.

The onMessage method has a single argument: the incoming message.

The signature of the onMessage method must follow these rules:

In the SimpleMessageBean class, the onMessage method casts the incoming message to a TextMessage and displays the text:

public void onMessage(Message inMessage) {
    TextMessage msg = null;

    try {
        if (inMessage instanceof TextMessage) {
            msg = (TextMessage) inMessage;
            logger.info("MESSAGE BEAN: Message received: " +
                msg.getText());
        } else {
            logger.warning("Message of wrong type: " +
                inMessage.getClass().getName());
        }
    } catch (JMSException e) {
        e.printStackTrace();
        mdc.setRollbackOnly();
    } catch (Throwable te) {
        te.printStackTrace();
    }
}

Packaging, Deploying, and Running the simplemessage Example

To package, deploy and run this example, go to the tut-install/javaeetutorial5/examples/ejb/simplemessage/ directory.

Creating the Administered Objects for the simplemessage Example

This example requires the following:

If you have run the simple JMS examples in Chapter 31, The Java Message Service API and have not deleted the resources, you already have these resources and do not need to perform these steps.

You can use Ant targets to create the resources. The Ant targets, which are defined in the build.xml file for this example, use the asadmin command. To create the resources needed for this example, use the following commands:


ant create-cf
ant create-queue

These commands do the following:

The Ant targets for these commands refer to other targets that are defined in the tut-install/javaeetutorial5/examples/bp-project/app-server-ant.xml file.

Building, Deploying, and Running the simplemessage Application Using NetBeans IDE

    To build, deploy, and run the application using NetBeans IDE, do the following:

  1. In NetBeans IDE, choose Open Project from the File menu.

  2. In the Open Project dialog, navigate to tut-install/javaeetutorial5/examples/ejb/.

  3. Select the simplemessage folder.

  4. Select the Open as Main Project check box and the Open Required Projects check box.

  5. Click Open Project.

  6. Right-click the simplemessage project and choose Build.

    This task packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the dist directory.

  7. Right-click the project and choose Undeploy and Deploy.

  8. Right-click the project and choose Run.

    This command returns a JAR file named simplemessageClient.jar and then executes it.

The output of the application client in the Output pane looks like this:


Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
 check <install_dir>/domains/domain1/logs/server.log.

The output from the message-driven bean appears in the server log (domain-dir/logs/server.log), wrapped in logging information.


MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3

The received messages often appear in a different order from the order in which they were sent.

    Undeploy the application after you finish running the client. To undeploy the application, follow these steps:

  1. Click the Services tab.

  2. Expand the Servers node.

  3. Expand the Sun Java System Application Server node.

  4. Expand the Applications node.

  5. Expand the Enterprise Applications node.

  6. Right-click simplemessage and choose Undeploy.

To remove the generated files, right-click the simplemessage project and choose Clean.

Building, Deploying, and Running the simplemessage Application Using Ant

To create and package the application using Ant, use the default target for the build.xml file:


ant

This target packages the application client and the message-driven bean, then creates a file named simplemessage.ear in the dist directory.

By using resource injection and annotations, you avoid having to create deployment descriptor files for the message-driven bean and application client. You need to use deployment descriptors only if you want to override the values specified in the annotated source files.

To deploy the application and run the client using Ant, use the following command:


ant run

Ignore the message that states that the application is deployed at a URL.

The output in the terminal window looks like this:


running application client container.
Sending message: This is message 1
Sending message: This is message 2
Sending message: This is message 3
To see if the bean received the messages,
 check <install_dir>/domains/domain1/logs/server.log.

In the server log file, the following lines should be displayed, wrapped in logging information:


MESSAGE BEAN: Message received: This is message 1
MESSAGE BEAN: Message received: This is message 2
MESSAGE BEAN: Message received: This is message 3

The received messages often appear in a different order from the order in which they were sent.

Undeploy the application after you finish running the client. Use the following command:


ant undeploy

To remove the generated files, use the following command:


ant clean

Removing the Administered Objects for the simplemessage Example

After you run the example, you can use the following Ant targets to delete the connection factory and queue:


ant delete-cf
ant delete-queue

Creating Deployment Descriptors for Message-Driven Beans

By using resource injection and annotations, you avoid having to create a standard ejb-jar.xml deployment descriptor file for a message-driven bean. However, in certain situations you still need a deployment descriptor specific to the Application Server, in the file sun-ejb-jar.xml.

You are likely to need a deployment descriptor if the message-driven bean will consume messages from a remote system. You use the deployment descriptor to specify the connection factory that points to the remote system. The deployment descriptor would look something like this:

<sun-ejb-jar>
  <enterprise-beans>
    <ejb>
      <ejb-name>MessageBean</ejb-name>
      <mdb-connection-factory>
        <jndi-name>jms/JupiterConnectionFactory</jndi-name>
      </mdb-connection-factory>
    </ejb>
  </enterprise-beans>
</sun-ejb-jar>

The ejb element for the message-driven bean contains the following:

For an example of the use of such a deployment descriptor, see An Application Example That Consumes Messages from a Remote Server.