The Java EE 6 Tutorial, Volume I

Chapter 16 Running the Enterprise 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 15, Getting Started with Enterprise Beans, you built a stateless session bean named ConverterBean. This chapter examines the source code of four more session beans:

The cart Example

The cart example represents a shopping cart in an online bookstore, and uses a stateful session bean to manage the operations of the shopping cart. 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/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;
    }
}

Lifecycle Callback Methods

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

Lifecycle 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 a 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 an EJB JAR file that contains the enterprise bean class, a WAR file if the enterprise bean is packaged within a WAR, or in an EAR that contains an EJB JAR or a WAR file that contains an enterprise bean.

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/examples/ejb/.

  3. Select the cart folder.

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

  5. Click Open Project Folder.

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

This builds and packages the application into cart.ear, located in tut-install/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/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/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 Runtime 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 Singleton Session Bean Example: counter

The counter example demonstrates how to create a singleton session bean.

Creating a Singleton Session Bean

The javax.ejb.Singleton annotation is used to specify that the enterprise bean implementation class is a singleton session bean.

@Singleton
public class SingletonBean { ... }

Initializing Singleton Session Beans

The EJB container is responsible for determining when to initialize a singleton session bean instance unless the singleton session bean implementation class is annotated with the javax.ejb.Startup annotation. This is sometimes called eager initialization. In this case, the EJB container must initialize the singleton session bean upon application startup. The singleton session bean is initialized before the EJB container delivers client requests to any enterprise beans in the application. This allows the singleton session bean to perform, for example, application startup tasks.


Example 16–1 An Eagerly Initialized Singleton Session Bean

The following singleton session bean stores the status of an application, and is eagerly initialized:

@Startup
@Singleton
public class StatusBean {
  private String status;

  @PostConstruct
  void init {
    status = "Ready";
  }
  ...
}

Sometimes multiple singleton session beans are used to initialize data for an application, and therefore must be initialized in a specific order. In these cases, use the javax.ejb.DependsOn annotation to declare the startup dependencies of the singleton session bean. The @DependsOn annotation's value attribute is one or more strings that specify the name of the target singleton session bean. If more than one dependent singleton bean is specifies in @DependsOn, the order that they are listed is not necessarily the order that the EJB container will initialize the target singleton session beans.


Example 16–2 Specifying the Ordering Of Singleton Session Bean Initialization

The following singleton session bean, PrimaryBean should be started up first:

@Singleton
public class PrimaryBean { ... }

SecondaryBean depends on PrimaryBean:

@Singleton
@DependsOn("PrimaryBean")
public class SecondaryBean { ... }

This guarantees that the EJB container will initialize PrimaryBean before SecondaryBean.



Example 16–3 Specifying Multiple Dependent Singleton Session Beans

The following singleton session bean, TertiaryBean, depends on PrimaryBean and SecondaryBean:

@Singleton
@DependsOn("PrimaryBean", "SecondaryBean")
public class TertiaryBean { ... }

SecondaryBean explicitly requires PrimaryBean to be initialized before it is initialized (through it's own @DependsOn annotation). In this case, the EJB container will first initialize PrimaryBean, then SecondaryBean, and finally TertiaryBean.

If, however, SecondaryBean did not explicitly depend on PrimaryBean, the EJB container may initialize either PrimaryBean or SecondaryBean first. That is, the EJB container could initialize the singletons in the following order: SecondaryBean, PrimaryBean, TertiaryBean.


Managing Concurrent Access in a Singleton Session Bean

Singleton session beans are designed for concurrent access, or situations where many clients need to access a single instance of a session bean at the same time. A singleton's client only needs a reference to a singleton in order to invoke any business methods exposed by the singleton, and doesn't need to worry about any other clients that may be simultaneously invoking business methods on the same singleton.

When creating a singleton session bean there are two ways of controlling concurrent access to the singleton's business methods: container-managed concurrency and bean-managed concurrency.

The javax.ejb.ConcurrencyManagement annotation is used to specify either container-managed or bean-managed concurrency for the singleton. @ConcurrencyManagement requires a type attribute to be set, one of javax.ejb.ConcurrencyManagementType.CONTAINER or javax.ejb.ConcurrencyManagementType.BEAN. If no @ConcurrencyManagement annotation is present on the singleton implementation class, the EJB container default of container-managed concurrency is used.

Container-Managed Concurrency

If a singleton uses container-managed concurrency, the EJB container controls client access to the business methods of the singleton. The javax.ejb.Lock annotation and a javax.ejb.LockType type are used to specify the access level of the singleton's business methods or @Timeout methods.

Annotate a singleton's business or timeout method using @Lock(READ) if the method can be concurrently accessed, or shared, with many clients. Annotate the business or timeout method with @Lock(WRITE) if the singleton session bean should be locked to other clients while a client is calling that method. Typically, the @Lock(WRITE) annotation is used when clients are modifying the state of the singleton.

Annotating a singleton class with @Lock specifies that all the business methods and any timeout methods of the singleton will use the specified lock type unless they explicitly set the lock type with a method-level @Lock annotation. If no @Lock annotation is present on the singleton class, the default lock type of @Lock(WRITE) is applied to all business and timeout methods.


Example 16–4 Specifying Container-Managed Concurrency in a Singleton Session Bean

The following example shows how to use the @ConcurrencyManagement, @Lock(READ), and @Lock(WRITE) annotations for a singleton that uses container-managed concurrency.

Although by default singletons use container-managed concurrency, the @ConcurrencyManagement(CONTAINER) annotation may be added at the class level of the singleton to explicitly set the concurrency management type.

@ConcurrencyManagement(CONTAINER)
@Singleton
public class ExampleSingletonBean {
  private String state;

  @Lock(READ)
  public String getState() {
    return state;
  }

  @Lock(WRITE)
  public void setState(String newState) {
    state = newState;
  }
}

The getState method can be accessed by many clients at the same time, because it is annotated with @Lock(READ). When the setState method is called, however, all the methods in ExampleSingletonBean will be locked to other clients because setState is annotated with @Lock(WRITE). This prevents two clients from attempting to simultaneously change the state variable of ExampleSingletonBean.



Example 16–5 Using Class- and Method-Level @Lock Annotations in a Singleton Session Bean

The getData and getStatus methods in the following singleton are of type READ, and the setStatus method is of type WRITE:

@Singleton
@Lock(READ)
public class SharedSingletonBean {
  private String data;
  private String status;

  public String getData() {
    return data;
  }

  public String getStatus() {
    return status;
  }

  @Lock(WRITE)
  public void setStatus(String newStatus) {
    status = newStatus;
  }
}

If a method is of locking type WRITE, client access to all the singleton's methods are blocked until the current client finishes its method call, or an access timeout occurs. When an access timeout occurs, the EJB container throws a javax.ejb.ConcurrentAccessTimeoutException. The javax.ejb.AccessTimeout annotation is used to specify the number of milliseconds before an access timeout occurs. If @AccessTimeout is added at the class level of a singleton, it specifies the access timeout value for all methods in the singleton unless a method explicitly overrides the default with its own @AccessTimeout annotation.

The @AccessTimeout annotation can be applied to both @Lock(READ) and @Lock(WRITE) methods.

@AccessTimeout has one required element, value, and one optional element, timeUnit. By default, the value is specified in milliseconds. To change the value unit, set timeUnit to one of the java.util.concurrent.TimeUnit constants: MICROSECONDS, MILLISECONDS, MICROSECONDS, or SECONDS.


Example 16–6 Setting the Access Timeout in a Singleton

The following singleton has a default access timeout value of 120,000 milliseconds, or 2 minutes. The doTediousOperation method overrides the default access timeout and sets the value to 360,000 milliseconds, or 6 minutes.

@Singleton
@AccessTimeout(value=120000)
public class StatusSingletonBean {
  private String status;

  @Lock(WRITE)
  public void setStatus(String new Status) {
    status = newStatus;
  }

  @Lock(WRITE)
  @AccessTimeout(value=360000)
  public void doTediousOperation {
    ...
  }
}


Example 16–7 Setting the Access Timeout in a Singleton in Seconds

The following singleton has a default access timeout value of 60 seconds, specified using the TimeUnit.SECONDS constant.

@Singleton
@AccessTimeout(value=60, timeUnit=SECONDS)
public class StatusSingletonBean { ... }

Bean-Managed Concurrency

Singletons that use bean-managed concurrency allow full concurrent access to all the business and timeout methods in the singleton. The developer of the singleton is responsible for ensuring that the state of the singleton is synchronized across all clients. Developers who create singletons with bean-managed concurrency are allowed to use the Java programming language synchronization primitives like synchronization and volatile to prevent errors during concurrent access.


Example 16–8 Specifying Bean-Managed Concurrency in a Singleton Session Bean

Add a @ConcurrencyManagement annotation at the class level of the singleton to specify bean-managed concurrency.

@ConcurrencyManagement(BEAN)
@Singleton
public class AnotherSingletonBean { ... }

Handling Errors in a Singleton Session Bean

If a singleton session bean encounters an error when it is initialized by the EJB container, that singleton instance will be destroyed.

Unlike other enterprise beans, once a singleton session bean instance is initialized it is not destroyed if the singleton's business or lifecycle methods cause system exceptions. This ensures that the same singleton instance is used throughout the application lifecycle.

The Architecture of the counter Example

The counter example consists of a singleton session bean, CounterBean, and a JavaServer Faces Facelets web front-end.

CounterBean is a simple singleton with one method, getHits, that returns an integer representing the number of times a web page has been accessed. Here is the code of CounterBean:

package counter.ejb;

import javax.ejb.Singleton;

/**
 *
 * @author ian
 * CounterBean is a simple singleton session bean that records the number
 * of hits to a web page.
 */
@Singleton
public class CounterBean {
    private int hits = 1;

    // Increment and return the number of hits
    public int getHits() {
        return hits++;
    }
}

The @Singleton annotation marks CounterBean as a singleton session bean. CounterBean uses a local, no-interface view.

CounterBean uses the EJB container's default metadata values for singletons to simplify the coding of the singleton implementation class. There is no @ConcurrencyManagement annotation on the class, so the default of container-managed concurrency access is applied. There is no @Lock annotation on the class or business method, so the default of @Lock(WRITE) is applied to the only business method, getHits. The following version of CounterBean is functionally equivalent to the version above:

package counter.ejb;

import javax.ejb.Singleton;
import javax.ejb.ConcurrencyManagement;
import static javax.ejb.ConcurrencyManagementType.CONTAINER;
import javax.ejb.Lock;
import javax.ejb.LockType.WRITE;

/**
 *
 * @author ian
 * CounterBean is a simple singleton session bean that records the number
 * of hits to a web page.
 */
@Singleton
@ConcurrencyManagement(CONTAINER)
public class CounterBean {
    private int hits = 1;

    // Increment and return the number of hits
    @Lock(WRITE)
    public int getHits() {
        return hits++;
    }
}

The web-front end of counter consists of a JSF managed bean, Count.java, that is used by the Facelets XHTML files template.xhtml and template-client.xhtml. The Count JSF managed bean obtains a reference to CounterBean through dependency injection. Count defines a hitCount JavaBeans property. When the getHitCount getter method is called from the XHTML files, CounterBean's getHits method is called to return the current number of page hits.

Here's the Count managed bean class:

@ManagedBean
@SessionScoped
public class Count {
    @EJB
    private CounterBean counterBean;

    private int hitCount;

    public Count() {
        this.hitCount = 0;
    }

    public int getHitCount() {
        hitCount = counterBean.getHits();
        return hitCount;
    }

    public void setHitCount(int newHits) {
        this.hitCount = newHits;
    }
}

The template.xhtml and template-client.xhtml files are used to render a Facelets view that displays the number of hits to that view. The template-client.xhtml file uses an expression language statement, #{count.hitCount}, to access the hitCount property of the Count managed bean. Here is the content of template-client.xhtml:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        
        This text above will not be displayed.
        
        <ui:composition template="/template.xhtml">
            
            This text will not be displayed.
            
            <ui:define name="title">
                This page has been accessed #{count.hitCount} time(s).
            </ui:define>
            
            This text will also not be displayed.
            
            <ui:define name="body">
                Hooray!
            </ui:define>
            
            This text will not be displayed.
            
        </ui:composition>
        
        This text below will also not be displayed.
        
    </body>
</html>

    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/examples/ejb/.

  3. Select the cart folder.

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

  5. Click Open Project Folder.

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

Building, Deploying, and Running the counter Example

The counter example application can be built, deployed, and run using NetBeans IDE or Ant.

ProcedureBuilding, Deploying, and Running the counter Example in NetBeans IDE

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

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

  3. Select the counter folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project Folder.

  6. In the Projects tab, right-click the counter project and select Run.

    A web browser will open the URL http://localhost:8080/counter that displays the number of hits.

  7. Click the browser's Refresh button to see the hit count increment.

ProcedureBuilding, Deploying, and Running the counter Example Using Ant

  1. In a terminal, navigate to tut-install/examples/ejb/counter.

  2. Enter the following command:


    ant all

    This will build and deploy counter to your Enterprise Server instance.

  3. In a web browser, enter the following URL: http://localhost:8080/counter.

  4. Click the browser's Refresh button to see the hit count increment.

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/examples/ejb/.

  3. Select the helloservice folder.

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

  5. Click Open Project Folder.

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

This builds and packages to application into helloservice.ear, located in tut-install/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/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 according to a calendar schedule, 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.

There are two types of enterprise bean timers: programmatic timers and automatic timers. Programmatic timers are set by explicitly calling one of the timer creation methods of the TimerService interface. Automatic timers are created upon the successful deployment of an enterprise bean that contains a method annotated with the java.ejb.Schedule or java.ejb.Schedules annotations.

Creating Calendar-Based Timer Expressions

Timers can be set according to a calendar-based schedule, expressed using a syntax similar to the UNIX cron utility. Both programmatic and automatic timers can use calendar-based timer expressions.

Table 16–1 Calendar-Based Timer Attributes

Attribute 

Description 

Allowable Values 

Default Value 

Examples 

second

One or more seconds within a minute. 

0 to 59

0

second="30"

minute

One or more minutes within an hour. 

0 to 59

0

minute="15"

hour

One or more hours within a day. 

0 to 23

0

hour="13"

dayOfWeek

One or more days within a week. 

0 to 7 [Both 0 and 7 refer to Sunday.]

Sun, Mon, Tue, Wed, Thu, Fri, Sat

*

dayOfWeek="3"

dayOfWeek="Mon"

dayOfMonth

One or more days within a month. 

1 to 31

-7 to –1 [A negative number means the xth day or days before the end of the month.]

Last

[1st, 2nd, 3rd, 4th, 5th, Last] [Sun, Mon, Tue, Wed, Thu, Fri, Sat]

*

dayOfMonth="15"

dayOfMonth="-3"

dayOfMonth="Last"

dayOfMonth="2nd Fri"

month

One or more months within a year. 

1 to 12

Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec

*

month="7"

month="July"

year

A particular calendar year. 

A four-digit calendar year. 

*

year="2010"

Specifying Multiple Values in Calendar Expressions

You can specify multiple values in calendar expressions in the following ways:

Using Wildcards in Calendar Expressions

Setting an attribute to an asterisk symbol (*) represents all allowable values for the attribute.


Example 16–9 Calendar Expressions with Wildcards

The following expression represents every minute:

minute="*"

The following expression represents every day of the week:

dayOfWeek="*"

Specifying a List of Values

To specify two or more values for an attribute, use a comma (,) to separate the values. A range of values are allowed as part of a list. Wildcards and intervals, however, are not allowed.

Duplicates within a list are ignored.


Example 16–10 Calendar Expressions with a List of Values

The following expression sets the day of the week to Tuesday and Thursday:

dayOfWeek="Tue, Thu"

The following expression represents 4:00 AM, every hour from 9:00 AM to 5:00 PM using a range, and 10:00 PM:

hour="4,9-17,20"

Specifying a Range of Values

Use a dash character (-) to specify an inclusive range of values for an attribute. Members of a range cannot be wildcards, lists, or intervals. If the range is of the form x-x, it is equivalent to the single-valued expression x. If the range is of the form x-y and x is greater than y, it is equivalent to the expression x-maximum value, minimum value-y. That is, the expression begins at x, rolls-over to the beginning of the allowable values, and continues up to y.


Example 16–11 Calendar Expressions Using Ranges

The following expression represents 9:00 AM to 5:00 PM:

hour="9-17"

The following expression represents Friday through Monday:

dayOfWeek="5-1"

The following expression represents the 25th day of the month to the end of the month, and the beginning of the month to the 5th day of the month:

dayOfMonth="25-5"

It is equivalent to the following expression:

dayOfMonth="25-Last,1-5"

Specifying Intervals

The forward slash (/) constrains an attribute to a starting point and an interval. It is used to specify every N seconds, minutes, or hours within the minute, hour or day. For an expression of the form x/y, x represents the starting point and y represents the interval. The wildcard character may be used in the x position of an interval, and is equivalent to setting x to 0.

Intervals may only be set for second, minute, and hour attributes.


Example 16–12 Calendar Expressions Using Intervals

The following expression represents every 10 minutes within the hour:

minute="*/10"

It is equivalent to:

minute="0,10,20,30,40,50"

The following expression represents every two hours starting at noon:

hour="12/2"

Programmatic Timers

When a programmatic 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 optionally 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 Programmatic Timers

To create a timer, the bean invokes one of the create methods of the TimerService interface. The create methods of TimerService allow single-action, interval, or calendar-based timers to be created.

For single-action or interval timers, the expiration of the timer can be expressed either as a duration or an absolute time. The duration is expressed as a the number of milliseconds before a timeout event is triggered. To specify an absolute time, create a java.util.Date object and pass it to either the TimerService.createSingleActionTimer or TimerService.createTimer methods.


Example 16–13 Setting a Programmatic Timer Based On a Duration

The following code sets a programmatic timer that will expire in one minute (6000 milliseconds):

long duration = 6000;
Timer timer = timerService.createSingleActionTimer(duration, new TimerConfig());


Example 16–14 Setting a Programmatic Timer Based On an Absolute Time

The following code sets a programmatic timer that will expire at 12:05 PM on May 1st, 2010, specified as a java.util.Date:

SimpleDateFormatter formatter = new SimpleDateFormatter("MM/dd/yyyy 'at' HH:mm");
Date date = formatter.parse("05/01/2010 at 12:05");
Timer timer = timerService.createSingleActionTimer(date, new TimerConfig());

For calendar-based timers, the expiration of the timer is expressed as a javax.ejb.ScheduleExpression object, passed as a parameter to the TimerService.createCalendarTimer method. The ScheduleExpression class represents calendar-based timer expressions, and has methods that correspond to the attributes described in Creating Calendar-Based Timer Expressions.


Example 16–15 Using ScheduleExpression to Set a Timer

The following code creates a programmatic timer using the ScheduleExpression helper class:

ScheduleExpression schedule = new ScheduleExpression();
schedule.dayOfWeek("Mon");
schedule.hour("12-17, 23");
Timer timer = timerService.createCalendarTimer(schedule);

For details on the method signatures, see the TimerService API documentation at http://java.sun.com/javaee/6/docs/api/javax/ejb/TimerService.html.

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

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

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

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

Non-persistent programmatic timers are created by calling TimerConfig.setPersistent(false) and passing the TimerConfig object to one of the timer creation methods.

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.

Automatic Timers

Automatic timers are created by the EJB container when an enterprise bean that contains methods annotated with the @Schedule or @Schedules annotations is deployed. An enterprise bean can have multiple automatic timeout methods, unlike a programmatic timer where there can only be one method annotated with the @Timeout annotation in the enterprise bean class.

Automatic timers can be configured through annotations or through the ejb-jar.xml deployment descriptor.

The @Schedule and @Schedules Annotations

Adding a @Schedule annotation on an enterprise bean marks that method as a timeout method according to the calendar schedule specified in the attributes of @Schedule.

The @Schedule annotation has elements that correspond to the calendar expressions detailed in Creating Calendar-Based Timer Expressionsand the persistent, info, and timezone elements.

The optional persistent element takes a boolean value, and is used to specify whether the automatic timer should survive a server restart or crash. By default, all automatic timers are persistent.

The optional timezone element is used to optionally specify that the automatic timer is associated with a particular time zone. If set, this element will evaluate all timer expressions in relation to the specified time zone, regardless of the time zone in which the EJB container is running. By default, all automatic timers set are in relation to the default time zone of the server.

The optional info element is used to set an informational description of the timer. A timer's information can be retrieved later using Timer.getInfo.


Example 16–16 Setting an Automatic Timer Using @Schedule

The following timeout method uses @Schedule to set a timer that will expire every Sunday at midnight:

@Schedule(dayOfWeek="Sun", hour="0")
public void cleanupWeekData() { ... }

The @Schedules annotation is used to specify multiple calendar-based timer expressions for a given timeout method.


Example 16–17 Setting Multiple Automatic Timers for a Timeout Method Using @Schedules

The following timeout method uses the @Schedules annotation to set multiple calendar-based timer expressions. The first expression sets a timer to expire on the last day of every month. The second expression sets a timer to expire every Friday at 11:00 PM.

@Schedules ({
    @Schedule(dayOfMonth="Last"),
    @Schedule(dayOfWeek="Fri", hour="23")
})
public void doPeriodicCleanup() { ... }

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/examples/ejb/timersession/src/java/ directory.

TimerSessionBean is a singleton session bean that shows how to set both an automatic timer and a programmatic timer. In the source code listing of TimerSessionBean that follows, the setTimer and @Timeout methods are used to set a programmatic timer. A TimerService instance is injected by the container when the bean is created. Because it’s a business method, setTimer is exposed to the local, no-interface view of TimerSessionBean and can be invoked by the client. In this example, the client invokes setTimer with an interval duration of 30,000 milliseconds. The setTimer method creates a new timer by invoking the createTimer method of TimerService. Now that the timer is set, the EJB container will invoke the programmaticTimeout method of TimerSessionBean when the timer expires, in about 30 seconds.

...
    public void setTimer(long intervalDuration) {
        logger.info("Setting a programmatic timeout for " +
                intervalDuration + " milliseconds from now.");
        Timer timer = timerService.createTimer(intervalDuration, 
                "Created new programmatic timer");
    }
    
    @Timeout
    public void programmaticTimeout(Timer timer) {
        this.setLastProgrammaticTimeout(new Date());
        logger.info("Programmatic timeout occurred.");
    }
...

TimerSessionBean also has an automatic timer and timeout method, automaticTimeout. The automatic timer is set to expire every 3 minutes, and is set using a calendar-based timer expression in the @Schedule annotation.

...
    @Schedule(minute="*/3", hour="*")
    public void automaticTimeout() {
        this.setLastAutomaticTimeout(new Date());
        logger.info("Automatic timeout occured");
    }
...

TimerSessoinBean also has two business methods, getLastProgrammaticTimeout and getLastAutomaticTimeout. Clients call these methods to get the date and time of the last timeout for the programmatic timer and automatic timer, respectively.

Here’s the source code for the TimerSessionBean class:

package timersession.ejb;

import java.util.Date;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.Schedule;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;


@Singleton
public class TimerSessionBean {
    @Resource
    TimerService timerService;

    private Date lastProgrammaticTimeout;
    private Date lastAutomaticTimeout;
    
    private Logger logger = Logger
            .getLogger("com.sun.tutorial.javaee.ejb.timersession.TimerSessionBean");
    
    public void setTimer(long intervalDuration) {
        logger.info("Setting a programmatic timeout for " +
                intervalDuration + " milliseconds from now.");
        Timer timer = timerService.createTimer(intervalDuration, 
                "Created new programmatic timer");
    }
    
    @Timeout
    public void programmaticTimeout(Timer timer) {
        this.setLastProgrammaticTimeout(new Date());
        logger.info("Programmatic timeout occurred.");
    }

    @Schedule(minute="*/3", hour="*")
    public void automaticTimeout() {
        this.setLastAutomaticTimeout(new Date());
        logger.info("Automatic timeout occured");
    }

    public String getLastProgrammaticTimeout() {
        if (lastProgrammaticTimeout != null) {
            return lastProgrammaticTimeout.toString();
        } else {
            return "never";
        }
        
    }

    public void setLastProgrammaticTimeout(Date lastTimeout) {
        this.lastProgrammaticTimeout = lastTimeout;
    }

    public String getLastAutomaticTimeout() {
        if (lastAutomaticTimeout != null) {
            return lastAutomaticTimeout.toString();
        } else {
            return "never";
        }
    }

    public void setLastAutomaticTimeout(Date lastAutomaticTimeout) {
        this.lastAutomaticTimeout = lastAutomaticTimeout;
    }
}

Note –

Enterprise Server has a default minimum timeout value of 1000 milliseconds, or 1 second. If you need to set the timeout value lower than 1000 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.

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

Follow these instructions to build, package, and deploy the timersession example to your Enterprise 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/examples/ejb/.

  3. Select the timersession folder.

  4. Select the Open as Main Project check box.

  5. Click Open Project Folder.

  6. Select Run->Run Main Project.

    This builds and packages the application into timersession.war, located in tut-install/examples/ejb/timersession/dist/, deploys this WAR file to your Enterprise Server instance, and then runs the web client.

ProcedureBuilding, 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/examples/ejb/timersession/ directory.

  2. To build timersession, type the following command:


    ant build
    

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

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


    ant deploy
    

ProcedureRunning the Web Client

  1. Open a web browser to http://localhost:8080/timersession.

  2. Click the Set Timer button to set a programmatic timer.

  3. Wait for a while and click the browser's Refresh button.

    You will see the date and time of the last programmatic and automatic timeouts.

    You can also see the messages that are logged when a timeout occurs by opening the server.log file located in domain-dir/server/logs/.

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.