Building EJB 3.0 applications with WebSphere Application Server

Using the WebSphere Application Server V6.1 Feature Pack for Enterprise JavaBeans 3.0

EJB™ 3.0 is a major step forward in simplifying application development in the enterprise. By using the IBM® WebSphere® Application Server V6.1 Feature Pack for Enterprise JavaBeans™ 3.0, you can benefit from the simplified development experience, new persistence model, and new features such as interceptors, while still deploying to a robust WebSphere platform. This content is part of the IBM WebSphere Developer Technical Journal.

Share:

Roland Barcia, Senior Technical Staff Member, IBM

Jeffrey Sampson (jrsamps@us.ibm.com), WebSphere Technical Sales Specialist, IBM

Jeffrey Sampson is a Consulting IT Specialist in Worldwide WebSphere Technical Sales. He has worked extensively with WebSphere Application Server and since its inception. His background includes 19 year of experience in application design and development for platforms ranging from embedded systems through distributed and mainframe based environments.



12 December 2007

Also available in Chinese

Introduction

Enterprise JavaBeans 3.0 is a major enhancement to the EJB specification, introducing a new POJO-based programming model that greatly simplifies development. The EJB 3.0 specification was created under JSR 220, and is divided into three documents:

  • EJB 3.0 Simplified API: Defines the new simplified API used to code EJB components; specifically, session beans and message-driven beans.
  • Enterprise JavaBeans Core Contracts and Requirements: Defines the EJB contracts between the bean and the EJB container.
  • Persistence API: Defines the new Persistence Model for Java.

This article introduces you to the IBM WebSphere Application Server V6.1 Feature Pack for EJB 3.0, and shows you how to build a Java Persistence API (JPA) and session bean POJO from scratch, plus how to run it inside WebSphere Application Sever. To highlight aspect oriented programming enhancements to the EJB 3.0 specification, this article will also walk you through building an additional session bean, demonstrating POJO injection, and help you build an EJB 3.0 interceptor.

This article uses the WebSphere Application Server Toolkit V6.1 and the Dali plug-in available from Eclipse. IBM Rational® Application Developer V7.5 was released as an open beta bundled with the Eclipse Dali functionality, so you might want to consider looking into that. You will notice future articles use Rational Application Developer V7.5 to build EJB 3.0 applications.

Preparation

In this article, you will build an EJB 3.0 application within WebSphere Application Server V6.1 using the new Feature Pack for EJB 3.0. For this example, the sample application is a simple customer order system, in which a customer creates an order, adds line items, and then submits the order. Figure 1 illustrates the use cases in this sample system, and the sequence in which the use cases are executed is shown in the activity diagram in Figure 2.

Figure 1. Sample application use cases
Figure 1. Sample application use cases
Figure 2. Sample application use case sequence
Figure 2. Sample application use case sequence

This article assumes:

  • WebSphere Application Server V6.1 is installed.
  • WebSphere Application Server V6.1 Feature Pack for Enterprise JavaBeans 3.0 has been downloaded.
  • WebSphere Application Server Toolkit v6.1 is installed.
  • Database schema and test data has been configured. (The DDL for populating a Derby database is provided in the download materials for this article.)

Install the feature pack

To deploy EJB 3.0 applications inside WebSphere Application Server V6.1, you need to install the EJB 3.0 Feature Pack. This section summarizes highlights of installing the Feature Pack onto an existing WebSphere Application Server V6.1. Be sure to check the Feature Pack Read Me file for other prerequisites. The steps below explain how to install the Feature Pack for EJB 3.0 into a simple configuration consisting of a single application server profile. For planning and installation guidance for installing to a Network Deployment configuration, refer to the links on the results panel of the installation wizard. (For complete installation instructions, see the WebSphere Application Server Information Center)

  1. Locate the EJB3 directory in your feature pack install image. Double-click install.exe to launch the installation wizard.

  2. On the Welcome panel of the installation wizard, verify that you are installing the EJB3 feature pack by clicking Next.

  3. Accept the terms of the licence agreement and click Next.

  4. A prerequisite check is performed. The feature pack installation image also contains two required fixpacks and will prompt you to install them if they are not present. Click Next to continue the installation.

  5. Use the Browse button to navigate to the WebSphere Application Server installation directory.

  6. If the application server is still running you might be presented with the perquisite error message shown in Figure 3. If so, go Back and stop the application server manually. After the application server is stopped, click Next again on the preceding panel to continue.

    Figure 3. Prerequisite Error
    Figure 3. Prerequisite Error
  7. A summary panel will display next, listing the items to be installed (Figure 4). Click Next to install the feature pack.

    Figure 4. Installation Summary
    Figure 4. Installation Summary
  8. When the installation completes, the panel shown in Figure 10 will display. Un-check Launch the Profile management tool and click Finish. (Links with instructions and considerations for installing the feature pack to a Network Deployment topology are also available on this panel.)

    Figure 5. Launch Profile Manager
    Figure 5. Launch Profile Manager

Add Dali to the Application Server Toolkit

Dali is a Object/Relational mapping plug-in for Eclipse that provides a Java™ Persistence perspective that supports top-down, bottom-up, and meet-in-the-middle O/R mapping. Dali also provides wizards and edit boxes for managing various Java Persistence API (JPA) annotations. Dali can be added to either the WebSphere Application Server Toolkit or Rational Application Developer V7.0.x. (Keep in mind that Dali is an open source plug-in so support comes from Eclipse. You can also use the Rational Application Developer V7.5 Beta as an alternative, which comes with the Dali plug-in installed. SeeResources for more.)

To add Dali to the Application Server Toolkit:

  1. Download the latest 0.5 version of Dali.
  2. Make sure that the Application Server Toolkit is stopped.
  3. Extract the contents of the Dali download file to the main Application Server Toolkit installation directory. (This is done because the file contains the directory path starting with the eclipse subdirectory that resides in the Application Server Toolkit install directory.)
  4. From a command prompt, go to the Application Server Toolkit install directory and use this command to start the toolkit:
    ast.exe -clean
    This command will make sure the Dali plug-in will be detected.

A simple example

You are now ready to build your first EJB 3.0 application for WebSphere Application Server. By following the steps in this section, you will develop a simple JPA POJO and a session bean using the example described earlier, and then test the scenario:

  1. Set up the development environment
  2. Create your first JPA POJO
  3. Create a simple sessions bean
  4. Import the client

A. Set up the development environment

  1. First, you need to create the desired projects:

    1. From the J2EE Perspective in the Application Server Toolkit, right-click within the Project Explorer and select New => Enterprise Application Project (Figure 6).

      Figure 6. New Enterprise Application Project
      Figure 6. New Enterprise Application Project
    2. In the New EAR Application Project wizard under the Target Runtime section, click New.

    3. In the New Server Runtime wizard (Figure 12), select WebSphere Application Server v6.1 and click Next.

      Figure 7. WebSphere Application Server v6.1 runtime
      Figure 7. WebSphere Application Server v6.1 runtime
    4. Enter the name of the WebSphere Application Server installation directory, if yours is different than the default. Click Finish.

    5. Name the project OrderSystem and ensure that the Target Runtime is WebSphere Application Server v6.1 (Figure 8). (Do not select the stub option). Press Finish.

      Figure 8. EAR Application Project Wizard
      Figure 8. EAR Application Project Wizard
    6. Your EAR file should display an error because there are no Java EE modules. EJB 3.0 is a plain POJO model, so you will create a simple Java project as a utility project that will contain your EJB 3.0 POJOs.

    7. Right-click the OrderSystem EAR and select New=>Other (Figure 9).

      Figure 9. Create new project
      Figure 9. Create new project
    8. Expand J2EE => Utility Project and click Next (Figure 10). A utility project is a plain Java project that is packaged within the EAR. You will mark this project as an EJB module later in the application.xml.

      Figure 10. Select Utility Project
      Figure 10. Select Utility Project
    9. Name the project OrderSystemEJB (Figure 11). Ensure that the EAR Project Name matches the already created EAR project.

      Figure 11. Utility Project Wizard
      Figure 11. Utility Project Wizard
  2. You now need to update the EAR file so that it sees the Java project as an EJB Module:

    1. Expand the OrderSystem and double click the Deployment Descriptor Editor (Figure 12).

      Figure 12. Open Deployment Descriptor
      Figure 12. Open Deployment Descriptor
    2. Go to the source tab, shown in Figure 13. Add these XML fragments after the display name tag:

      <module>
      	<ejb>OrderSystemEJB.jar</ejb>
      </module>

      The result should look similar to Figure 13

      Figure 13. application.xml
      Figure 13. application.xml
    3. Save the editor and close the Application Deployment Descriptor.

  3. Add the local WebSphere Application Server to the Application Server Toolkit workspace as a server:

    • In the J2EE perspective, go to the Servers tab. Right-click within the servers list and select New=>Server (Figure 14).

      Figure 14. New Server
      Figure 14. New Server
    • Accept the defaults, then Next.

    • Un-check Run server with resources within the workspace, then Finish.

      Figure 15. WebSphere Server Settings
      Figure 15. WebSphere Server Settings
    • Right-click on the new server and select Start.

  4. Add a data source for the Derby database that you populated with the CUSTSCH schema provided in CUSTSCH-derby.ddl:

    • Right-click on the server and select Run administrative console (Figure 16).

      Figure 16. Launch administrative console
      Figure 16. Launch administrative console
    • In the administrative console, navigate to Resources=>JDBC=>Data sources.

    • Select a scope for the data source (Figure 17). What you choose will vary depending on your installation. Select a server scope for your local server, then click New.

      Figure 17. Create a DataSource
      Figure 17. Create a DataSource
    • On the Step 1 panel (Figure 18), enter Order DS for the Data source name and jdbc/orderds for the JNDI name, then Next.

      Figure 18. DataSource wizard
      Figure 18. DataSource wizard
    • On the Step 2 panel (Figure 19), select Create new JDBC Provider, then Next.

      Figure 19. JDBC Provider
      Figure 19. JDBC Provider
    • On the Step 2.1 panel (Figure 20), select the following values:

      • Database type: Derby
      • Provider type: Derby Network Server Using Derby Client
      • Implementation type: Connection pool data source

      Enter optional Description text, then click Next.

      Figure 20. JDBC Provider
      Figure 20. JDBC Provider
    • On the Step 3 panel (Figure 21), enter JPATEST for the database name, then Next.

      Figure 21. Database Specific Properties
      Figure 21. Database Specific Properties
    • On the Step 4 panel (Figure 22), review the data to make sure all values were entered correctly, then click Finish.

      Figure 22. Summary
      Figure 22. Summary
    • Save your changes by clicking the Save link at the top of the page.

    • Verify that the Derby network database is running, then select the Order DS data source and click Test Connection (Figure 23).

      Figure 23. Test Connection
      Figure 23. Test Connection
    • You should receive a message at the top of the panel similar to that shown in Figure 24

      Figure 24. Connection Confirmation
      Figure 24. Connection Confirmation

B. Create your first JPA POJO

The EJB 3.0 specification defines a new persistence architecture, called the Java Persistence Architecture (JPA), that enables you to map simple POJOs to relational databases. JPA POJOs are no longer EJB components. Instead, the EJB 3.0 spec defines how JPA objects are managed in an EJB 3.0 container. However, JPA applications can run inside a Java SE environment as well. In this example, you will to create a JPA object that runs inside WebSphere Application Server.

  1. First, create a simple POJO:

    1. Expand the OrderSystemEJB project. Right-click on the src directory and select New => Class (Figure 25).

      Figure 25. New Class
      Figure 25. New Class
    2. In the New Java Class panel (Figure 26), store the class in the Package called com.ibm.ejb3.order.entities, name the class Customer, then Finish.

      Figure 26. Class Wizard
      Figure 26. Class Wizard
    3. Create two simple properties:

      • customerId: int
      • name: String
      package com.ibm.ejb3.order.entities;
      
      import java.io.Serializable;
      
      public class Customer implements Serializable 
      {
      	private int customerId;
      	private String name;
      }
    4. In the Ourtline view, right-click on the Customer class, then select Source => Generate Getters and Setters (Figure 27).

      Figure 27. Generate Getters and Setters
      Figure 27. Generate Getters and Setters
    5. Click Select All and OK (Figure 28).

      Figure 28. Select properties
      Figure 28. Select properties
    6. The result is a simple POJO, as shown in Figure 29.

      Figure 29. Customer Class
      Figure 29. Customer Class
  2. You are now ready to make your POJO a JPA entity. In most cases, all you need is a good Java editor. This example uses the editor in Eclipse that you use to create JPA applications:

    1. Over the class declaration, begin typing @Enti, then press Ctrl-Space to trigger the Eclipse content assist. Select @Entity. (Figure 30)

      Figure 30. Entity Annotation
      Figure 30. Entity Annotation
    2. An Entity class needs a primary key. Over the customerId property, add the @Id annotation (Figure 31).

      Figure 31. Id Annotation
      Figure 31. Id Annotation
  3. If your property names match that of the database, you are done and you have your first JPA POJO. However, the schema in this example is slightly different, and you will use the JPA Eclipse tools for help:

    1. Switch to the Java Persistence perspective. You can begin the Open Perspective wizard by right-clicking on the perspective icons in the upper right corner of the panel and selecting Other. (Figure 32)

      Figure 32. Open Other
      Figure 32. Open Other
    2. Select Java Persistence from the list that displays.

    3. Go to the Database Explorer view. To load your database, right-click on Connections, then select New => Connection... (Figure 33)

      Figure 33. New Connection
      Figure 33. New Connection
    4. Enter or select the following properties (Figure 34):

      • Uncheck Use default naming convention
      • Connection Name: OrderDB
      • Database Manager: Derby => 10.1
      • Database Name: JPATEST
      • Class Location: navigate to Derby lib directory (for example: \WebSphere\AppServer\derby\lib\derbyclient.jar)
      • User Id and Password: Enetr appropriate values for your system.
      Figure 34. Connection Parameters
      Figure 34. Connection Parameters
    5. Navigate to OrderDB => JPATEST => Schemas => CUSTSCH => Tables => CUSTOMER and examine the fields (Figure 35).

      Figure 35. CUSTOMER Table
      Figure 35. CUSTOMER Table
  4. You need to add the persistence.xml file to the JPA project. This file is the JPA deployment descriptor for configuring JPA Properties. You can use the JPA development tools for this:

    1. In the Package Explorer view, right-click OrderSystemEJB and select Java Persistence => Add Java Persistence... (Figure 36)

      Figure 36. Add Java Persistence support
      Figure 36. Add Java Persistence support
    2. For Connection, select OrderDB, and for Schema, select CUSTSCH. (The connection could have timed out. If so, select the Reconnect... link and enter the same user ID and password). For Persistence unit name, enter OrderDB (Figure 37).

      Figure 37. JPA Project Content
      Figure 37. JPA Project Content
    3. Once you do this, your Customer POJO will have an error because the Eclipse JPA plug-in will detect a mismatch between the database model and the JPA object model. You will fix this in the next step.

    4. Open the META-INF folder of OrderSystemEJB, and open the newly generated persistence.xml (Figure 38).

      Figure 38. persistence.xml
      Figure 38. persistence.xml
    5. You need to add the data source to the JPA provider. Open persistence.xml and click on the Source tab. Add this xml tag within the persistence-unit tag, as shown in Figure 39:

      <jta-data-source>jdbc/orderds</jta-data-source>
      Figure 39. Adding DataSource
      Figure 39. Adding DataSource
    6. Save and close persistence.xml. (Because you are running inside a Java EE container, the default provider will be used.)

  5. Because the database does not match exactly with your POJO, you need to fix your mappings a bit:

    1. In the Outline view, select the customerId property.

    2. In the lower right corner of the panel, ensure that Map As is set to Id. Under Column Name, select CUST_ID. Ensure the rest of the fields match the values shown in Figure 40.

      Figure 40. Persistence Properties
      Figure 40. Persistence Properties
    3. Select the PK Generation tab. Check the Primary Key Generation and select Identity for Strategy (Figure 41). JPA enables a few strategies for automatic primary key generation. In this case, JPA will delegate to DB2's identity feature.

      Figure 41. Identity Strategy
      Figure 41. Identity Strategy
    4. In the Customer POJO, you need to override the default schema name because the database is stored in a different schema. Add the @Table annotation as shown in Figure 42. Add CUSTOMER for name and CUSTSCH for schema.

      Figure 42. Set Schema
      Figure 42. Set Schema
    5. Save and close Customer.java.

C. Create a simple sessions bean

Much like JPA, all of EJB 3.0 has been simplified with a POJO programming model, making EJB 3.0 easy to code. Below, you will create a simple session bean that uses the JPA API to access the Customer JPA POJO.

  1. First, you need to create a simple interface; having an interface is usually a good practice. Otherwise, the EJB provider will generate one for you. In this exercise, you will just create a simple Interface.

    1. Under the OrderSystemEJB project, right-click the src folder and select New=>Interface (Figure 43).

      Figure 43. New Interface
      Figure 43. New Interface
    2. For Package name, enter or browse to com.ibm.ejb3.order.session. For class name, enter CustomerTask (Figure 44).

      Figure 44. Interface Wizard
      Figure 44. Interface Wizard
    3. Add the method below to the interface, then Finish.

      public Customer findCustomer(int customerId) throws CustomerDoesNotExist ;
    4. You should have an error, because there is no class called CustomerDoesNotExist. Use the Eclipse suggestion to create the class, as in Figure 45.

      Figure 45. Create Exception
      Figure 45. Create Exception
    5. Make sure that Constructors from superclass is checked and that the superclass is java.lang.Exception (Figure 46).

      Figure 46. Class Wizard
      Figure 46. Class Wizard
    6. Next, add a @Local annotation above the class declaration, as shown in the Figure 47. This makes your session bean a local EJB.

      Figure 47. Local Annotation
      Figure 47. Local Annotation
    7. Right click in the editor and select Source => Organize Imports (Figure 48)

      Figure 48. Adding Imports
      Figure 48. Adding Imports
  2. Next, you will create your Session Bean POJO:

    1. Right-click the com.ibm.ejb3.order.session package and select New => Class (Figure 49).

      Figure 49. New Class
      Figure 49. New Class
    2. Name the class CustomerTaskImpl, and add the CustomerTask interface to the Interface list (Figure 50).

      Figure 50. Class Wizard
      Figure 50. Class Wizard
    3. To make CustomerTaskImpl a session bean, add an @Stateless annotation, as shown in Figure 51. This makes your POJO a stateless session bean.

      Figure 51. Stateless Annotation
      Figure 51. Stateless Annotation
  3. An EJB 3.0 container is also an injection server. To have persistence actions, you need an entity manager. This can be easily added to the session bean through injection. When using JPA within an EJB 3.0 container, the container automatically manages passing the correct persistence context for you. This is known as a container managed entity manager. Using JPA in this fashion, the EJB 3.0 container will properly manage the lifecycle of the persistence context, and propagate the correct context across EJB invocations.

    1. Add the EntityManager declaration shown below to the CustomerTaskImpl class.

      @PersistenceContext(name="OrderDB")
      EntityManager em;
    2. You can use code assist to bring in the PersistenceContext Import (Figure 52).

      Figure 52. PersistenceContext Annotation
      Figure 52. PersistenceContext Annotation
    3. Add this code snippet to the findCustomer method:

      Customer customer = (Customer) em.find(Customer.class, customerId);
      if (customer == null) {
      	throw new CustomerDoesNotExist("Customer does not exist");
      }
      return customer;
    4. Organize imports as before (Figure 53), then save and close the file.

      Figure 53. Customer implementation
      Figure 53. Customer implementation

D. Import the client

Next, you will import a simple WAR file with a servlet that will be used to test your session bean and JPA object. The servlet demonstrates how easy it is to access a session bean from Web applications. A simple WAR file is included with this article with the code already in place.

  1. Import the Web application and examine the code:

    1. From the File Menu, select File => Import.

    2. In the Import wizard, expand Web => WAR File (Figure 54).

      Figure 54. Import WAR File
      Figure 54. Import WAR File
    3. For WAR file, Browse to the location where you saved the provided OrderClient.war file. Keep the default name for the Web project, and ensure that OrderSystem is the EAR Project Name (Figure 55).

      Figure 55. Select EAR Project to Import to
      Figure 55. Select EAR Project to Import to
  2. Next, you can examine the servlet code.

    1. Expand the Java Resources: src folder and open the EJBClientServlet.java file (Figure 56).

      Figure 56. Test Servlet
      Figure 56. Test Servlet
    2. Notice that the EJB session bean can be injected right into the servlet.

      public class EJBClientServlet extends javax.servlet.http.HttpServlet 
      implements javax.servlet.Servlet {
          /* (non-Java-doc)
      	 * @see javax.servlet.http.HttpServlet#HttpServlet()
      	 */	
      	
      	@EJB
      	private CustomerTask customerTask = null;
    3. In the displayCustomerAndOrder method, notice that once you have the session bean instance, it is just simple Java.

      private void displayCustomerAndOrder(int customreId, PrintWriter out) throws 
      	CustomerDoesNotExist {
      Customer customer = customerTask.findCustomer(customreId);
      out.println("<br>Customer ID => " + customer.getCustomerId());
      	out.println("<br>Customer Name => " + customer.getName());
  3. You will now deploy and test the application:

    1. From the J2EE perspective, go to the Servers view, right-click the server and press Start (Figure 57).

      Figure 57. Start the Server
      Figure 57. Start the Server
    2. Once the server is started, right-click the server again and select Add and Remove Projects... (Figure 58)

      Figure 58. Add the Project
      Figure 58. Add the Project
    3. Add the OrderSystem application by selecting the application from the Available projects list on the left and press Add (Figure 59).

      Figure 59. Move project
      Figure 59. Move project
    4. Back in the Project Explorer view, expand the Deployment Descriptor => Servlets, then right-click EJBClientServlet and select Run As => Run on Server (Figure 60).

      Figure 60. Run the Servlet
      Figure 60. Run the Servlet
    5. Select Choose an existing server and check the Set server as project default option, then Finish (Figure 61).

      Figure 61. Associate Server as default
      Figure 61. Associate Server as default
    6. The browser should display the Customer ID and Customer Name (Figure 62).

      Figure 62. Examine Browser
      Figure 62. Examine Browser
    7. Close the browser and remove the project from the server (Figures 63 and 64)

      Figure 63. Remove the Project
      Figure 63. Remove the Project
      Figure 64. Remove the Project
      Figure 64. Remove the Project
    8. Close and save all the files.


Advanced EJB features

EJB 3.0 provides a simple programming model without compromising function. The fundamental principal is to use default values, and only override where you must. For example, EJB 3.0 still permits XML configuration. XML deployment descriptors can override annotations so you can externalize configurations and override settings for different deployment environments. In this section, you will continue to use annotations, but will add more functionality to the application to see some other features of EJB 3.0. (The application used here was designed solely for illustrating different EJB 3.0 and JPA features, and not to be an example of application design best practices.)

The steps in this section:

  1. Building JPA objects
  2. Build another session bean
  3. Add an interceptor
  4. Test the application

A. Building JPA objects

The steps below show how to use the JPA Eclipse tools to generate more JPA POJOs, after which you will update the mappings to customize for the use case.

  1. The JPA Eclipse tools support top-down, meet-in-the-middle, and bottom-up mappings. You will use the bottom-up tools to generate the remaining entities:

    1. In the Package Explorer view, right-click OrderSystemEJB and select Java Persistence => Generate Entities (Figure 65).

      Figure 65. Generate Entities
      Figure 65. Generate Entities
    2. Select your Connection (your database connection may have closed by now; select the Reconnect link and enter your credentials again, if necessary), and select the CUSTSCH schema. Press Next (Figure 66).

      Figure 66. Select Connection and Schema
      Figure 66. Select Connection and Schema
    3. On the Generate Entities from Tables panel, only select LINEITEM, CUSTORDER, and PRODUCT. Make sure your Package name is com.ibm.ejb3.order.entities. Since the CUSTORDER table name is different than the Entity Name ("Order," which is the desired name of the entity), enter Order as the Entity name for CUSTORDER (Figure 67). Press Finish.

      Figure 67. Select the Tables
      Figure 67. Select the Tables
  2. Next, you will update the mappings:

    1. Open the Order entity (Figure 68).

      Figure 68. Examine Order Class
      Figure 68. Examine Order Class
    2. Use the Java Persistence Properties Editor or add the annotations marked below in bold:

      • @Table annotation is needed to override the schema name.
      • @NamedQuery is adding a query to your JPA POJO. JPA has a very rich query language you can use, called EJB-QL. This query is asking for an open order from the customer.
      • The ordered property needs to be annotated as an ID, as you did before. Also, you are adding a generation strategy of Identity.
      • Finally, notice the Order has a relationship to LineItems. You will add a fetch rule of Eager. This means that when someone asks for an order, the JPA engine will fetch all the line items that are associated with the order as well.
      @Entity
      @Table(name="CUSTORDER", schema="CUSTSCH")
      @NamedQuery(name="getCurrentOrder",
      query="select o from Order o where o.customerId = :customerId and 
      	o.status ='OPEN'")
      public class Order implements Serializable {
      @Id
      	@Column(name="ORDER_ID")
      	@GeneratedValue(strategy=GenerationType.IDENTITY)
      	private int orderId;
      
      	private String status;
      
      	private double total;
      
      	@Column(name="CUSTOMER_ID")
      	private int customerId;
      
      	@OneToMany(mappedBy="orderId",fetch=FetchType.EAGER)
      	private Set<Lineitem> lineitemCollection;
  3. You need to update the Customer entity to have a relationship to Order. The requirements of the system are such that a Customer has only one open Order. You want to create a relationship to that open Order. You do not want to generate the relationship because a Customer has many orders, but only when he has one Open Order.

    1. Open the Customer entity. Add Order currentOrder, as shown in the code below. Generate the setters and getters using the Eclipse Java tools.

      package com.ibm.ejb3.order.entities;
      
      import java.io.Serializable;
      import javax.persistence.Entity;
      import javax.persistence.Id;
      import javax.persistence.GeneratedValue;
      import javax.persistence.GenerationType;
      import javax.persistence.Column;
      import javax.persistence.Table;
      
      @Entity
      @Table(name="CUSTOMER", schema="CUSTSCH")
      public class Customer implements Serializable {
      	
      	@Id
      	@GeneratedValue(strategy=GenerationType.IDENTITY)
      	@Column(name="CUST_ID")
      	private int customerId;
      	private String name;
      	
      	
      private Order currentOrder;
      	
      	public int getCustomerId() {
      		return customerId;
      	}
      	public void setCustomerId(int customerId) {
      		this.customerId = customerId;
      	}
      	public String getName() {
      		return name;
      	}
      	public void setName(String name) {
      		this.name = name;
      	}
      	public Order getCurrentOrder() {
      		return currentOrder;
      	}
      	public void setCurrentOrder(Order currentOrder) {
      		this.currentOrder = currentOrder;
      	}
      
      }
    2. Add the following @OneToOne and @JoinColumn annotations, as shown below.

      • Notice that the fetch rule is set to lazy, so you will not fetch the order when someone asks for the customer.
      • You have set some cascading rules. If someone updates the open order, changes will cascade as defined.
      • The relationship is optional, which means the customer will not always have an open order.
      • You have specified the Join column (the name corresponds to the foreign key on the Customer table, while the referencedColumn name corresponds to the primary key of the Custorder table.) If you do not specify the Join column, JPA will attempt to resolve the keys based on a naming scheme.
      @OneToOne(fetch=FetchType. LAZY,cascade = 
      	{CascadeType.MERGE,CascadeType.REFRESH},optional=true )
      	
      @JoinColumn(name="OPEN_ORDER_ID",referencedColumnName="ORDER_ID")
      private Order currentOrder;
    3. Update the LineItem class to point to the correct schema, as you did for Customer and Order (Figure 69).

      Figure 69. LineItem Schema
      Figure 69. LineItem Schema
    4. Similarly, override the schema for Product (Figure 70).

      Figure 70. Product Schema
      Figure 70. Product Schema
    5. Save and close the entities.

B. Build another session bean

Here, you will build another session bean to see how you can inject another session bean into it.

  1. As before, create an interface:

    1. In the session package, select New => Interface (Figure 71) and name the Interface OrderTask. Click Finish.

      Figure 71. New Interface
      Figure 71. New Interface
    2. Annotate the class as Local, and add the getCurrentOrder method, as shown below.

      package com.ibm.ejb3.order.session;
      
      import com.ibm.ejb3.order.entities.Order;
      
      @Local
      public interface OrderTask {
      	public Order getCurrentOrder(int customerId) throws CustomerDoesNotExist;
      }
  2. Create a new stateless session bean.

    1. Right-click the session's package and select New => Class (Figure 72).

      Figure 72. New Class
      Figure 72. New Class
    2. Make sure the class implements the OrderTask Interface you just created (Figure 73).

      Figure 73. OrderTaskImpl
      Figure 73. OrderTaskImpl
    3. Annotate the bean as stateless. Add the code in bold below. Notice that you can inject the CustomerTask into the OrderTask. This greatly simplifies things by avoiding JNDI lookup code. Also, you are also injecting an entity manager, as you did before.

      package com.ibm.ejb3.order.session;
      
      import javax.ejb.EJB;
      import javax.ejb.Stateless;
      
      import com.ibm.ejb3.order.entities.Order;
      
      @Stateless
      public class OrderTaskImpl implements OrderTask {
      	
      	@EJB(beanName = "CustomerTaskImpl")
      	CustomerTask customerTask;
      
      @PersistenceContext(name="OrderDB")
      	EntityManager em;
      
      public Order getCurrentOrder(int customerId) throws CustomerDoesNotExist {
      		// TODO Auto-generated method stub
      		return null;
      	}
      
      }
    4. Finally, add the code in bold below to the getCurrentOrder method. Notice how easy it is to access queries. Also notice that the order method interacts with the Customer object. It is important to understand that because both classes are using @PersistenceContext, they will get proper propagation of the Entity Manager.

      public Order getCurrentOrder(int customerId) throws CustomerDoesNotExist {
      	Query query = em.createNamedQuery("getCurrentOrder");
      	query.setParameter(1, customerId);
      	Order currentOrder = (Order)query.getSingleResult();
      	if(currentOrder != null)
      	{
      		Customer customer = customerTask.findCustomer(customerId);
      		Order alreadySet = customer.getCurrentOrder();
      		if(alreadySet == null)
      		{
      			customer.setCurrentOrder(currentOrder);
      		}	
      	}
      	return currentOrder;
      }
    5. Don't forget to organize your imports.

C. Add an interceptor

EJB 3.0 also adds the ability to use Aspect Oriented Programming techniques in your application. EJB 3.0 supports interceptors, which enable you to intercept code for cross cutting techniques. Next, you will create an audit interceptor that displays the customer's actions on the administrative console.

  1. Create a simple Audit class:

    1. Create a class called AuditInterceptor (Figure 74).

      Figure 74. New Java Class
      Figure 74. New Java Class
    2. Add the code below in bold. @AroundInvoke tells the container what method to call when the interceptor intercepts. The code accesses the customerId and method name and displays them.

      Click to see code listing

      package com.ibm.ejb3.order.session;
      
      import java.lang.reflect.Method;
      
      import javax.interceptor.AroundInvoke;
      import javax.interceptor.InvocationContext;
      
      public class AuditInterceptor {
      	
      	@AroundInvoke
      	public Object audit(InvocationContext invocationContext) throws Exception
      	{
      		Method operation = invocationContext.getMethod();
      		String name = operation.getName();
      		Object param[] = invocationContext.getParameters();
      		System.out.println("Customer Id " + param[0] + " executing operation => " + name);
      		return invocationContext.proceed();
      	}
      
      }
  2. You can add the interceptor to the session beans by annotating the class with the @Interceptor annotation. You will do this for simplicity in this exercise, but it is often a best practice for a class not to be aware of who is intercepting it. EJB 3.0 supports partial XML deployment descriptors where you can define interceptor bindings that externalize matching an interceptor to a class. It is usually best to externalize interceptors.

    1. Open the OrderTaskImpl class and add the @Interceptors (AuditInterceptors.class), as shown below.

      @Stateless
      @Interceptors(AuditInterceptor.class)
      public class OrderTaskImpl implements OrderTask {
    2. Do the same for the CustomerTask.

      @Stateless
      @Interceptors(AuditInterceptor.class)
      public class CustomerTaskImpl implements CustomerTask {

D. Test the application

You need to modify the client to invoke the new function:

  1. The code you need is provided with this article, but it is commented out. Uncomment the OrderTask declaration as shown below in bold.

    public class EJBClientServlet extends javax.servlet.http.HttpServlet implements 
    javax.servlet.Servlet {
        /* (non-Java-doc)
    	 * @see javax.servlet.http.HttpServlet#HttpServlet()
    	 */
    	
    	@EJB
    	private CustomerTask customerTask = null; 
    	
    	@EJB
    	private OrderTask orderTask = null;
    	 
    	public EJBClientServlet() {
    		super();
    	}  
    	
    	@Override
    	public void init() throws ServletException {
    		super.init();
    	}
  2. Uncomment the code in bold below. Notice that you access the Order and Iterate functions through the LineItems. The LineItems will be populated because of the eager fetching rule you set.

    private void displayCustomerAndOrder(int customerId, PrintWriter out) throws 
    CustomerDoesNotExist {
    	  Customer customer = customerTask.findCustomer(customerId);
          out.println("<br>Customer ID => " + customer.getCustomerId());
          out.println("<br>Customer Name => " + customer.getName());
    	      
          Order order = orderTask.getCurrentOrder(customerId);
          if(order != null)
          {
        	  out.println("<br>order id => " + order.getOrderId());
        	  out.println("<br>status => " + order.getStatus());
        	  out.println("<br>Total => " + order.getTotal());
        	  Collection<Lineitem> lineItems = order.getLineitemCollection();
        	  for(Lineitem lineItem: lineItems)
        	  {
        		  out.println("<br>****");
        		  out.println("<br>Line Item Id => " + lineItem.getLiId());
        		  out.println("<br>Quantity => " + lineItem.getQuantity());
        		  out.println("<br>Total => " + lineItem.getAmount());
        	  }
    
          }
          else
          {
        	  out.println("<br>Customer has no open order...");
          }
    
    }
  3. Add the project to the server as you did before (Figure 75).

    Figure 75. Add Project Again
    Figure 75. Add Project Again
  4. Run the servlet (Figure 76).

    Figure 76. Run on Server
    Figure 76. Run on Server
  5. The browser should display the customer, the current order, and all the line items (Figure 77).

    Figure 77. Examine Result
    Figure 77. Examine Result
  6. Finally, examine the console to see the print statements for the interceptor (Figure 78). You will notice the findCustomer task is called twice, once from the client and once from the order task, and the getCurrentOrder task is called once.

    Figure 78. Examine Interceptor result
    Figure 78. Examine Interceptor result

Conclusion

EJB 3.0 is a major step forward in simplifying application development in the enterprise. This article showed you how to build EJB 3.0 applications for WebSphere Application Server V6.1 using the simplified programming model, the new Java Persistence API, and interceptors. By using the EJB 3.0 Feature Pack for WebSphere Application Server, you can benefit from the simplified development experience, new persistence model, and new features such as interceptors, while still deploying to a robust WebSphere platform.


Acknowledgements

The authors wish to acknowledge Tom Alcott, Jim Knutson, Randy Schnier, Kevin Sutter, Tim Francis, and Keys Botzum for their contributions to the article.


Download

DescriptionNameSize
Code sampleWAS_EJB3_LAB.zip10 KB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Java technology
ArticleID=276613
ArticleTitle=Building EJB 3.0 applications with WebSphere Application Server
publish-date=12122007