Exercise 11.1: Stateless Session Bean




Exercise 11.1: Stateless Session Bean

This exercise utilizes the ProcessPayment EJB described in Chapter 11 of the EJB book. The code for this stateless bean is copied as is from Chapter 11, but a few additional classes are implemented to facilitate the example.

Start Up JBoss

If you already have JBoss running, there is no reason to restart it. Otherwise, start it up as instructed in Workbook 1.

Initialize the Database

The database tables will be created when Exercise 11.1 is deployed to JBoss. If you have problems running this example, shut down JBoss and run the clean.db Ant task.

Build and Deploy the Example Programs

Perform the following steps:

  1. Open a command prompt or shell terminal and change to the ex11_1 directory created by the extraction process.

    Set the JAVA_HOME and JBOSS_HOME environment variables to point to where your JDK and JBoss 4.0 are installed. Examples:


    Windows:

    C:\workbook\ex11_1> set JAVA_HOME=C:\jdk1.5.0
    C:\workbook\ex11_1> set JBOSS_HOME=C:\jboss-4.0.x
    


    Unix:

    $ export JAVA_HOME=/usr/local/jdk1.5.0
    $ export JBOSS_HOME=/usr/local/jboss-4.0
    

  2. Add ant to your execution path. Ant is the build utility.


    Windows:

    C:\workbook\ex11_1> set PATH=..\ant\bin;%PATH%
    


    Unix:

    $ export PATH=../ant/bin:$PATH
    

  3. Perform the build by typing ant.

As in the exercises in earlier chapters of this workbook, titan.jar is rebuilt, copied to the JBoss deploy directory, and redeployed by the application server.

Examine ProcessPaymentBean

com.titan.processpayment.ProcessPaymentBean is copied as is from Chapter 11. @Resource injection is very vendor-specific. Let's look at how JBoss supports this annotation:

package com.titan.processpayment;

import com.titan.domain.*;

import java.sql.*;

import javax.ejb.*;
import javax.annotation.Resource;
import javax.sql.DataSource;
import javax.ejb.EJBException;

@Stateless
public class ProcessPaymentBean implements ProcessPaymentRemote,
                                           ProcessPaymentLocal
{

   final public static String CASH = "CASH";
   final public static String CREDIT = "CREDIT";
   final public static String CHECK = "CHECK";

   @Resource(mappedName="java:/DefaultDS") 
 DataSource dataSource;

When you use the @javax.annotation.Resource annotation or its XML equivalent, <resource-ref>, JBoss requires that you specify the mappedName( ) attribute. JBoss stores all resources in its global JNDI tree. The mappedName( ) attribute expects a global JNDI name string. The java:/DefaultDS value references JBoss's default data source. Appendix A provides more detail on how to deploy your own data sources. The mappedName( ) attribute is used in the same way to inject JMS destinations and connection factories.

Examine DataAccessBean

com.titan.access.DataAccessBean is a simple stateless session bean that is used to find and create Customer entities. It also has methods to create and destroy the tables that are needed by the ProcessPayment EJB. We won't go over these because they are quite simple.

Examine the Client

The main client is the com.titan.clients.MakePayment class:

package com.titan.clients;

import com.titan.processpayment.*;
import com.titan.domain.Customer;
import com.titan.access.DataAccess;

import java.util.Calendar;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;

/**
 * Example demonstrating use of ProcessPayment EJB directly
 *
 */

public class MakePayment
{

   public static void main(String [] args)
   {
      try
      {
         // obtain CustomerHome
         Context jndiContext = getInitialContext( );
         DataAccess access = (DataAccess)jndiContext.lookup("DataAccessBean/remote");

         access.makePaymentDbTable( );
         Customer cust = new Customer( );
         cust.setFirstName("Bill");
         cust.setLastName("Burke");
         access.createCustomer(cust);

The client starts by getting a reference to the DataAccessBean's remote interface. It initializes the payment tables by calling the DataAccess.makePaymentDbTable( ) method and then creates a Customer entity:

         ProcessPaymentRemote procpay =
(ProcessPaymentRemote)jndiContext.lookup("ProcessPaymentBean/remote");

After obtaining a reference to the ProcessPayment EJB's remote interface, three separate payments are made by cash, check, and credit card for the Customer entity that was created:

         System.out.println("Making a payment using byCash( )..");
         procpay.byCash(cust,1000.0);

         System.out.println("Making a payment using byCheck( )..");
         CheckDO check = new CheckDO("010010101101010100011", 3001);
         procpay.byCheck(cust,check,2000.0);

         System.out.println("Making a payment using byCredit( )..");
         Calendar expdate = Calendar.getInstance( );
         expdate.set(2025,1,28); // month=1 is January
         CreditCardDO credit = new CreditCardDO("370000000000002",
                      expdate.getTime( ),"AMERICAN_EXPRESS");
         procpay.byCredit(cust,credit,3000.0);

         System.out.println("Making a payment using byCheck( ) with a low
check number..");
         CheckDO check2 = new CheckDO("111000100111010110101", 50);
         try
         {
            procpay.byCheck(cust,check2,9000.0);
            System.out.println("Problem! The PaymentException has not been raised!");
         }
         catch(PaymentException pe)
         {
            System.out.println("Caught PaymentException: "+pe.getMessage( ));
         }

The last bit of code tries to make a check payment with a check number that is too low. A payment exception is thrown in this instance.

         access.dropPaymentDbTable( );
      }
      catch(Throwable t)
      {
         t.printStackTrace( );
      }

   }

   static public Context getInitialContext( ) throws Exception
   {
      return new InitialContext( );
   }

}

The client finishes by dropping the payment table.

Run the Client Application

Run the MakePayment application by invoking ant run.payment at the command prompt. Remember to set your JBOSS_HOME and PATH environment variables. This is the output:

run.payment:
     [java] Making a payment using byCash( )..
     [java] Making a payment using byCheck( )..
     [java] Making a payment using byCredit( )..
     [java] Making a payment using byCheck( ) with a low check number..
     [java] Caught PaymentException: Check number is too low. Must be at least 100