Abridged Version of 'EJB Fundamentals' 
by Richard Monson-Haefel   

 edit P.Komisar  latest revision Nov / 2007
reference:http://developer.java.sun.com/developer/onlineTraining/EJBIntro


Richard Monson is a jGuru whose articles appear on the Sun site. He is
also the author
  he O'Reilly book 'Enterprise JavaBeans'  which enjoys a 5
star rating by it's
reviewers. If you are making a serious inquiry into EJBs
this would be a good book to
have.



Enterprise JavaBeans

Enterprise JavaBeans provide a programming model to build
and deploy server-side distributed, portable, transactional
software components called enterprise Javabeans.

The enterprise java beans are hosted in a program called a
container
from which the bean's remote services are provided
to network clients. The model is designed to make enterprise
beans portable between EJB containers provided by different
vendors.

// EJB 2.x adds 'local' services which makes beans available
// locally to components running on the same JVM


The EJB Container

The container hosts an enterprise bean in a manner similar how
serlets are managed in a web server application or applets are
hosted in a HTML browser. The EJB container also manages:

This separation of tasks, allows the bean developer to focus on
encapsulationg business rules.

The container isolates the enterprise bean from direct access by
the client. The container intercepts client method invocations to
apply  persistence, transactions, and security management
operations a client calls on a bean.

Containers manage many beans simultaneously using pooling to
reduce memory consumption. An unused bean may be pooled for
reuse by another client or removed from memory and brought back
when needed. This is transparent to the client whose reference has
been kept alive and reassociated with a new identical instance.

The bean depends on the container for all resource access. The
container provides three channels


Callback Methods

Every bean implements a subtype of the EnterpriseBean interface
which defines several methods,  called callback methods. Each
callback method alerts the bean to a different event in its lifecycle.
The container will invoke these methods to notify the bean when it's
about to activate the bean, persist its state to the database, end a
transaction, remove the bean from memory, etc.

The callback methods allow the bean to do housework immediately
before or after some event.


EJBContext

Every bean obtains an EJBContext object, which is a reference
to the container.The EJBContext interface provides methods for
interacting with the container so a bean can request information
about its environment like the identity of its client, the status of a
transaction, or to obtain remote references to itself.

Java Naming and Directory Interface

Java Naming and Directory Interface (JNDI) is a standard extension
to the Java platform for accessing naming systems like LDAP, NetWare,
file systems, etc. Every bean automatically  has access to a special
naming system called the Environment Naming Context (ENC). The
ENC is managed by the container and accessed by beans using
JNDI. The JNDI ENC allows a bean to access resources like JDBC
connections, other enterprise beans, and properties specific to that
bean.


Enterprise Beans

A bean is created to represent a business concept, like a
customer or a clerk  To create an EJB, a developer provides:

The bean implementation is instantiated at runtime in the
container to become a distributed object. The client accesses
this object over the network through the remote and home
interfaces. It is the clients actions that invoke a beans life
cycle, to create, manipulate, and remove beans from the EJB
server.

// EJB 2.x adds the local call vs the more expensive remote call


Remote and Home Interfaces

The home interface represents the life-cycle methods of the
component.

The remote interface represents the business method of the bean.

The remote and home interfaces extend the javax.ejb.EJBObject
and javax.ejb.EJBHome interfaces respectively. These EJB interface
types define a standard set of utility methods and provide common base
types for all remote and home interfaces.


The Remote interface hierarchy Used with EJBs  

                          java.rmi.Remote                                              // rmi interface level
                           |                       |
     javax.ejb.EJBObject         javax.ejb.EJBHome         // EJB specific interface level
                     |                                          |
         Bean's_Remote                 Bean's_Home       //  developer's defined extensions



How the Referencing Works


The home interface implementation is used to create
the bean. The methods of the remote interface execute
the business code.


Example
// from EJB Fundamentals  by R. Monson-Haefel

// ... obtain a reference that implements the home interface.
// Use the home interface to create a new instance of the Customer bean.
   Customer customer = home.create(customerID);
// using a business method on the Customer.
   customer.setName(someName);


The Remote Interface for the Above Example

import javax.ejb.EJBObject;
import java.rmi.RemoteException;  

public interface Customer extends EJBObject {

      public Name getName( ) throws RemoteException;
      public void setName(Name name) throws RemoteException;
      public Address getAddress( ) throws RemoteException;
      public void setAddress(Address address) throws RemoteException;
      } 
  //  Here the Customer remote interface is defined as extending javax.efb.EJBObject, 
 //  (which extends java.rmi.Remote) The interface defines bean's business methods

Entity & Session Beans

// data stored in a database and returned by get-set type methods are typically wrapped
// in entity beans while business operations are wrapped in session beans.

The remote interface defines accessor and mutator methods to
read and update information about a business concept. This is
typical of a an entity bean, representing a persistent business
object whose data is stored in a database. Entity beans wrap
business data with behavior specific to that data.

Although entity beans often have task-oriented methods, tasks
are more typical of session beans. Session beans do not represent
data. Instead they represent business processes or services.

A Session Bean Example
// modified from EJB Fundamentals by Richard Monson-Haefel

import javax.ejb.EJBObject;
  import java.rmi.RemoteException;

  public interface HotelClerk extends EJBObject {
    public void reserveRoom( Customer cust, RoomInfo ri ) throws RemoteException;
    public RoomInfo availableRooms( Location loc, DateInfo di) throws RemoteException;
    }

Entity Beans

Entity beans implement the javax.ejb.EntityBean which extends
javax. ejb.EnterpriseBean.

Entitiy Bean Example      
 // from EJB Fundamentals by Richard Monson-Haefel

 import javax.ejb.EntityBean;   
// note the implementation of  javax.ejb.EntityBean 

public class CustomerBean implements EntityBean {
           Address   myAddress;

           Name        myName;
           CreditCard  myCreditCard;

           public Name getName( ) {
              return myName;
              }
          public void setName(Name name) {
              myName = name;
              }
          public Address getAddress() {
               return myAddress;
              }
          public void setAddress(Address address) {
               myAddress = address;
               }    // other contents
         }

Session Beans

Session beans represent a set of processes or tasks,
typically calling on other beans or accessing a database
directly. Both behaviours

Session Bean Example    
// from EJB Fundamentals by Richard Monson-Haefel

import javax.ejb.SessionBean;  
// note the implementation of  javax.ejb.SessionBean 

  public class HotelClerkBean implements SessionBean {

 public void reserveRoom(Customer cust, RoomInfo ri, Date from, Date to) {
               CreditCard card = cust.getCreditCard( );
               RoomHome roomHome =  // ... get home reference
               Room room = roomHome.findByPrimaryKey(ri.getID());
               double amount = room.getPrice(from,to);
               CreditServiceHome creditHome =  // ... get home reference
               CreditService creditAgent = creditHome.create();
               creditAgent.verify(card, amount);
               ReservationHome resHome =  // ... get home reference
               Reservation reservation = resHome.create(cust,room,from,to);
               }

     public RoomInfo[] availableRooms(Location loc, Date from, Date to) {
              // Make an SQL call to find available rooms
              Connection con = // ... get database connection
              Statement stmt = con.createStatement( );
              ResultSet results = stmt.executeQuery("SELECT ...");
                       //      ...
              return roomInfoArray;
              }
      } 

Bean Classes Don't Implement the Remote or Home Interfaces

The bean classes do not implement the remote or home interfaces.
EJB doesn't require that the bean class implement these interfaces
and in fact it is discouraged. This is because the base types of the
remote and home interfaces (EJBObject and EJBHome) define a
lot of other methods that are implemented by the container
automatically
.

The bean class does provide implementations for all the business
methods defined in the remote as well as callback methods defined
in the home interface.


The Home Interface // life cycle create, find & destroy

The home interface provides life cycle methods for creating,
destroying, and locating beans. These methods are separated
out of the remote interface because they are general behaviours
not specific to a single bean instance.

Home Interface Example      
 // from EJB Fundamentals by Richard Monson-Haefel

import javax.ejb.EJBHome;
   import javax.ejb.CreateException;
   import javax.ejb.FinderException;
   import java.rmi.RemoteException;  // notice the javax.ejb.EJBHome extension

   public interface CustomerHome extends EJBHome {

         public Customer create(Integer customerNumber) 
                            throws RemoteException, CreateException;

         public Customer findByPrimaryKey(Integer customerNumber) 
                                         throws RemoteException, FinderException;

         public Enumeration findByZipCode(int zipCode) 
                                         throws RemoteException, FinderException;
                     }
 
Home Interface Methods

Following is a code sample showing the home interface methods
being used to find and create beans


Example
  // from EJB Fundamentals by Richard Monson-Haefel

CustomerHome home =  // Get a reference to the CustomerHome object 
     Customer customer =  home.create(new Integer(33));
     Name name = new Name("Richard", "Wayne", "Monson-Haefel");
     customer.setName(name);
     Enumeration enumOfCustomers = home.findByZip(55410);
     Customer customer2 = home.findByPrimaryKey(new Integer(33));
     Name name2 = customer2.getName( );
     // output is "Richard Wayne Monson-Haefel"
      System.out.println(name);
 

Enterprise Beans as Distributed Objects

The remote and home interfaces are types of Java RMI
Remote interfaces. An enterprise bean is an RMI-style
distributed object, accessible from applications in other
address spaces.

In EJB, the RMI 'skeleton' for the remote and home interfaces
are implemented by the container, not the bean class. 

Distributed object protocols define the format of network
messages sent between address spaces. Most EJB servers
support either the Java Remote Method Protocol (JRMP) or
CORBA's Internet Inter-ORB Protocol (IIOP), details of which
are hidden from the users of the EJB system.


Container and Bean Managed Persistence

The entity bean provides an object-oriented view of data
that will frequently be mapped to a relational database. 

There are two types of entity bean:

With CMP, thecontainer manages the persistence of the entity bean.
Vendor tools map entity fields to the database and no database
access code is written in the bean class.

With BMP, the entity bean contains database access code (usually
JDBC) and is responsible for reading and writing its own state to
the database.

BMP entities are notified by the container when it's necessary to
make an update or read its state from the database. The container
may also handle locking or transactions to maintain database integrity.


Container-Managed Persistence

Container-managed persistence beans is the simplest for the bean
developer to create and the most difficult for the EJB server to support.
All the logic for synchronizing the bean's state with the database is
handled automatically by the container. The bean developer doesn't
write any data access logic. Most EJB vendors support automatic
persistence to a relational database, but the level of support varies
greatly. // ~observation circa 2000


Details of CMP 

Notice in the following CMP bean example there is
no database access code. EJB server vendors provide
tools to map bean values to databases.

Bean Class  Example  // from EJB Fundamentals by Richard Monson-Haefel

 import javax.ejb.EntityBean;

 public class CustomerBean implements EntityBean {

     int        customerID;
    Address    myAddress;
    Name       myName;
    CreditCard myCreditCard;

   // CREATION METHODS
    public Integer ejbCreate(Integer id) {
        customerID = id.intValue( );
        return null;
       }
    public Customer ejbCreate(Integer id, Name name) {
        myName = name;
        return ejbCreate(id);
    }
    public void ejbPostCreate(Integer id) {     }
    public void ejbPostCreate(Integer id, Name name) {    }

    // BUSINESS METHODS
    public Name getName( ) {  return myName;    }
    public void setName(Name name) { myName = name;   }

    public Address getAddress( ) {  return myAddress;    }
    public void setAddress(Address address) { myAddress = address;   }

    public CreditCard getCreditCard( ) {   return myCreditCard;   }
    public void setCreditCard(CreditCard card) {  myCreditCard = card;    }

    // CALLBACK METHODS defined in EntityBean interface
    public void setEntityContext(EntityContext cntx) {    }
    public void unsetEntityContext() {    }

    public void ejbLoad( ) {    }
    public void ejbStore( ) {    }
    public void ejbActivate( ) {    }

    public void ejbPassivate( ) {    }
    public void ejbRemove( ) {    }
  
  }

Following are the objects referenced in the above beans
which ultimately use mostly String values which may in
turn represent other primitive Java types.

// The Name class
  public class Name implements Serializable {

    public String lastName, firstName, middleName;

    public Name(String lastName, String firstName, String middleName) {
        this.lastName   = lastName;
        this.firstName  = firstName;
        this.middleName = middleName;
       }
     public Name( ) { }  // also includes a  no-args empty default constructor
  }

 // The Address class
  public class Address implements Serializable {

    public String street, city, state, zip;

    public Address( String street, String city, String state, String zip) {
        this.street = street;
        this.city   = city;
        this.state  = state;
        this.zip    = zip;
       }
     public Address( ) { }    // no-args empty default constructor
  }

  // The CreditCard class
  public class CreditCard  implements Serializable {

  public String number, type, name;
  public Date expDate;

  public CreditCard ( String number, String type, String name, Date expDate) {
        this.number  = number;
        this.type    = type;
        this.name    = name;
        this.expDate = expDate;
       }
     public CreditCard( ) {}    // no-args empty default constructor
}

Container Managed Fields

These fields are called container-managed fields because
the container synchronizes their state with the database.
Container-managed
fields can be any primitive data types
or serializable type.

Not all fields in a bean are automatically container-managed
fields, such as plain instance fields for transient use within the
bean. The container-managed fields are differentiated from
plain instance fields
in the deployment descriptor.

The container-managed fields are mapped to corresponding
types such as columns in an RDBMS or through Object-Relational
mapping to an Object-Oriented Database
.

The CustomerBean / Container Mapping 

{
    id            INTEGER PRIMARY KEY,
    last_name     CHAR(30),
    first_name    CHAR(20),
    middle_name   CHAR(20),
    street        CHAR(50),
    city          CHAR(20),
    state         CHAR(2),
    zip           CHAR(9),
    credit_number CHAR(20),
    credit_date   DATE,
    credit_name   CHAR(20),
    credit_type   CHAR(10)
}


The Primary Key

A subset of the container-managed fields will server as the
bean's primary key, the pointer to a unique record in a database. 
In CustomerBean, the id field is the primary key field. Primitive
single field primary keys are represented as by their corresponding
object wrappers
, for example a primitive int in the bean class
manifests itself to a bean's client as a java.lang.Integer type.

A primary key made up of several fields are called compound
primary keys is represented by a special class defined by the
bean developer.
 

The Home Interface of the CMP Entity Beans
// from EJB Fundamentals  by R. Monson-Haefel  

public interface CustomerHome extends javax.ejb.EJBHome {

public Customer create( Integer customerNumber)
           throws RemoteException,CreateException;

public Customer create(Integer customerNumber, Name name)
           throws RemoteException,CreateException;

public Customer findByPrimaryKey(Integer customerNumber)
          throws RemoteException, FinderException;

public Enumeration findByZipCode(int zipCode)
          throws RemoteException, FinderException;
}

Example // How the Home interface is used by a client
// from EJB Fundamentals  by R. Monson-Haefel

CustomerHome home =  // Get a reference to the CustomerHome object
  Name name = new Name("John", "W", "Smith");
  Customer customer =  home.create( new Integer(33), name);
 

Creation of a New CMP Instance Entity Bean

Invoking the create method on the bean's home interface,
creates a new instance of a CMP entity bean and
inserts
data into the database. 

A bean's home interface may declare zero or more create( )
methods. Each must have corresponding ejbCreate( ) and
ejbPostCreate( ) methods in the bean class.

These creation methods are linked at runtime, so that when a
create( ) method is invoked on
the home interface, the container
delegates the invocation to the corresponding
ejbCreate( ) and
ejbPostCreate() methods on the bean class.

The ejbCreate( ) methods initialize the instance state before a
record is inserted into the database. When the ejbCreate( )
method is finished (returning null in CMP) the container reads
the container-managed fields and inserts a new record into the
CUSTOMER table indexed by the primary key.

// customerID  maps to the CUSOTMER.ID column.

In EJB, an entity bean doesn't technically exist until after it's data
has been inserted into the database. Once inserted,  the entity
bean exists and can access its own primary key and remote
references. A bean needing to access its own primary key or
remote reference after its created, but before it services any
business methods, may use it's ejbPostCreate( ) method which
allows the bean to do any post-create processing before it
begins serving client requests
.

Find Methods

Methods in the home interface that begins with "find" are called
the find methods, and are used  to query the EJB server for
specific entity beans
, based on the name of the method and
arguments passed in. In CMP entity beans, the find methods
do not have matches in the bean class as the container provides
them. The deployer will use vendor-specific tools to utilize the
container provided find methods.

Types of Find Methods


Remote Interface

Beside the home interface, an entity bean must define a
remote interface defining the entity's business methods.

Customer Remote Interface Example
// from EJB Fundamentals  by R. Monson-Haefel  

import javax.ejb.EJBObject;
  import java.rmi.RemoteException;

  public interface Customer extends EJBObject {

    public Name getName( ) throws RemoteException;
    public void setName(Name name) throws RemoteException;

    public Address getAddress( ) throws RemoteException;
    public void setAddress(Address address) throws RemoteException;

    public CreditCard getCreditCard( ) throws RemoteException;
    public void setCreditCard(CreditCard card) throws RemoteException;
    }

 How Used

Customer customer = // ... obtain a remote reference to the bean
// get the customer's address
Address addr = customer.getAddress( );
// change the zip code
addr.zip = "56777";
// update the customer's address
customer.setAddress(addr);

The business methods in the remote interface are
delegated to the matching business methods in the
bean instance. In the Customer bean. Business
methods can be simple or complex as required.

Callback Methods

Aside from implement Remote Interface business methods
and Home Interface create methods, the bean class also
implements a set of callback methods that allow the container
to notify the bean of events in its lifecycle.

The callback methods are defined in the javax.ejb.EntityBean
interface implemented by all entity beans. The EntityBean
interface has the following definition. Notice that the bean
class implements these methods.

public interface javax.ejb.EntityBean {

    public void setEntityContext();
    public void unsetEntityContext();
    public void ejbLoad();
    public void ejbStore();
    public void ejbActivate();
    public void ejbPassivate();
    public void ejbRemove();

}

EntityBean Methods

ejbLoad( ) & ejbStore Example
// from EJB Fundamentals  by R. Monson-Haefel 

// going to and from object field identifiers and table names 

public void ejbLoad( ) {
        if (myName == null)
            myName = new Name( );
           myName.lastName = lastName;
          // other fields
          }

    public void ejbStore( ) {
        lastName   = myName.lastName;
        //  other fields
    }

Passivation - The disassociation of an bean instance with its
remote reference so the container can evict it from memory or
reuse it. A resource conservation measure to reduce the number
of instances in memory.

The ejbPassivate() and ejbActivate() methods notify the bean
when it is about to be passivated or activated. 


Bean-Managed Persistence

BMP beans manage synchronizing their state with a database.
The bean usually uses JDBC to read and write its fields to the
database. The container tells it when to do each synchronization
operation and manages the transactions for the bean automatically.

Bean-managed persistence is useful when persistence operations
are too complicated for the container or to use a data source that
is not supported by the container such as custom or legacy databases.

Monson-Haefel's CustomerBean can be modified to be a BMP
Persistence bean without impacting the remote or home interfaces
at all. In fact, the original CustomerBean is not modified directly.

Instead, extension and overriding the appropriate methods is used.
(In most cases, you would not extend a bean to make it BMP, instead
just implementing as a BMP bean directly.) This strategy does allow
the bean to be act as either a CMP or BMP bean.

Customer Bean Class Extension

public class CustomerBean_BMP  extends CustomerBean {
                         public void ejbLoad( ) { // override implementation }
                         public void ejbStore() {  // override implementation }
                         public void ejbCreate() {// override implementation}
                         public void ejbRemove() {// override implementation}
                         private Connection getConnection() { // override implementation}
                        } 


How Does It Do It?  

A BMP bean manages its own persistence by including database
access logic in it's versions of the ejbLoad( ) and ejbStore( ) methods.
These methods are called on the bean when the EJB server 'thinks'
it is appropriate to read or write data. The ejbLoad() method is usually
invoked by the container at the beginning of a transaction, just before
the container delegates a business method to the bean. The code
below shows how to implement the ejbLoad( ) method using JDBC.

ejbLoad( ) method overridden to provide Bean Managed Persistence via JDBC
// condensed from an example in EJB Fundamentals  by R. Monson-Haefel 
      
public void ejbLoad( ) {

                    Connection con;
                    try {
                      Integer primaryKey =  (Integer)ejbContext.getPrimaryKey();
                      con = this.getConnection();
                      Statement sqlStmt = con.createStatement("SELECT * FROM Customer " +
                                                         " WHERE customerID = " +  primaryKey.intValue());
                     ResultSet results = sqlStmt.executeQuery();
                       if (results.next( )) {
                     // get the name information from the customer table
                        myName = new Name();
                        myName.first = results.getString("FIRST_NAME");
                        myName.last = results.getString("LAST_NAME");
                        myName.middle = results.getString("MIDDLE_NAME");
                        //  the address and credit card info are left out for the sake of brevity
                        }
                     }
                     catch (SQLException sqle) {throw new EJBException(sqle);  }
                         finally { if (con!=null) con.close( );}
                  }
              }
 
 

In the ejbLoad() method, use the ejbContext( ) reference to the bean's
EntityContext to obtain the instance's primary key. This ensures that you
use the correct index to the database. Tthe CustomerBean_BMP will
need to use the inherited setEntityContext() and unsetEntityContext( )
methods as illustrated earlier.

ejbStore( ) overridden to provide Bean Managed Persistence with JDBC
// condensed from an example in EJB Fundamentals  by R. Monson-Haefel   

  public void ejbStore() {
              Connection con;
               try { Integer primaryKey = (Integer)ejbContext.getPrimaryKey( );
                con = this.getConnection();
                PreparedStatement sqlPrep = con.prepareStatement("UPDATE customer set " +
                  "last_name = ?, first_name = ?,  middle_name = ?, " + 
                  "street = ?, city = ?, state = ?,   zip = ?, " +
                  "card_number = ?, card_date = ?, " +
                  "card_name = ?, card_name = ?, " +
                  "WHERE id = ?"
                           );
                           sqlPrep.setString(1,myName.last);
                           sqlPrep.setString(2,myName.first);
                           sqlPrep.setString(3,myName.middle);
                           sqlPrep.setString(4,myAddress.street);
                           sqlPrep.setString(5,myAddress.city);
                           sqlPrep.setString(6,myAddress.state);
                           sqlPrep.setString(7,myAddress.zip);
                           sqlPrep.setInt(8, myCreditCard.number);
                           sqlPrep.setString(9, myCreditCard.expDate); 
                           sqlPrep.setString(10, myCreditCard.type);
                           sqlPrep.setString(11, myCreditCard.name);
                           sqlPrep.setInt(12,primaryKey.intValue());
                           sqlPrep.executeUpdate();
                         }
                         catch (SQLException sqle) {throw new EJBException(sqle);  }
                         finally { if (con!=null) con.close( );  }
                  }
       }   

The ejbStore() method is invoked by the container on the bean,
at the end of a transaction, just before the container attempts to
commit all changes to the database.


The getConnection( ) Method

The getConnection( ) method is not a standard EJB method.
It is a private helper method implemented to conceal the mechanics
of obtaining a database connection. Below is the definition of the
getConnection( ) method.

The getConnection( ) Method Code

  private Connection getConnection( ) throws SQLException {
      InitialContext jndiContext = new InitialContext( );
      DataSource source = (DataSource) jndiContext.lookup("java:comp/env/jdbc/myDatabase");
      return source.getConnection();
     }
 }

Note this uses the JNDI lookup syntax rather than the typical
JDBC equivalent code. Database connections are obtained
from the container using a default JNDI context called the JNDI
Environment Naming Context (ENC). The ENC provides access
to transactional, pooled JDBC connections through the standard
connection factory, the javax.sql.DataSource type.


Inserting and Removing Entities in the Database

The ejbCreate( ) and ejbRemove( ) methods are implemented with
similar database access logic. The ejbCreate( ) methods inserts
a new record into the database and the ejbRemove( ) methods
delete the entities data from the database, using SQL INSERT
and DELETE commands.

ejbCreate( ) & ejbRemove ( ) BMP Examples
// from EJB Fundamentals  by R. Monson-Haefel 

    public void ejbCreate(Integer id) {
           this.customerID = id.intValue();
           Connection con;
           try {
                 con = this.getConnection();
                 Statement sqlStmt =
                con.createStatement("INSERT INTO customer id VALUES (" + customerID + ")");
                sqlStmt.executeUpdate();
                return id;
               }
               catch(SQLException sqle) {throw new EJBException(sqle);    }
                  finally { if (con!=null)  con.close(); }
                 }

      public void ejbRemove( ) {
            Integer primaryKey = (Integer)ejbContext.getPrimaryKey( );
            Connection con;
             try {
             con = this.getConnection();
             Statement sqlStmt = con.createStatement
             ("DELETE FROM customer WHERE id = " primaryKey.intValue( ));
             sqlStmt.executeUpdate();
             }
            catch(SQLException sqle) {throw new EJBException(sqle);  }
                         finally { if (con!=null) con.close( ); }
                       }

In BMP, the bean class is responsible for implementing the find
methods defined in the home interface. For each find method
defined in the home interface there must be corresponding
ejbFind( ) method in the bean class. The ejbFind( ) methods
locate the appropriate bean records in the database and return
their primary keys to the container. The container converts
the primary keys into bean references and returns them to the client.


BMP Find Method Example
// from EJB Fundamentals  by R. Monson-Haefel 

public Integer ejbFindByPrimaryKey( Integer primaryKey)
            throws ObjectNotFoundException {
              Connection con;
               try {
                    con = this.getConnection();
                     Statement sqlStmt =con.createStatement("SELECT * FROM Customer " +
                                              " WHERE customerID = " + primaryKey.intValue( ));
                     ResultSet results = sqlStmt.executeQuery();
                         if (results.next())
                            return primaryKey;
                        else
                            throw ObjectNotFoundException();
                         }
                         catch (SQLException sqle) { throw new EJBException(sqle);   }
                         finally { if (con!=null)  con.close( ); }
                     }

// Single-entity find methods return a single primary key or throw the ObjectNotFoundException

     public Enumeration ejbFindByZipCode( int zipCode)  {
                         Connection con;
                         try {
                             con = this.getConnection();
                             Statement sqlStmt =
                             con.createStatement("SELECT id FROM Customer " +
                                   " WHERE zip = " +zipCode);
                             ResultSet results = sqlStmt.executeQuery( );
                             Vector keys = new Vector();
                             while(results.next()){
                                 int id = results.getInt("id");
                                 keys.addElement(new Integer(id));
                                }
                                 return keys.elements( );
                         }
                    catch (SQLException sqle) { throw new EJBException(sqle); }
                    finally { if (con!=null) con.close(); }
                }

// If no matching bean records are found, an empty collection is returned


Session Type Enterprise Beans

Session beans manage the interactions of entity and other session
beans, access resources, and generally perform tasks on behalf of
the client. Session beans are not persistent business objects and
do not represent data in the database. Session beans correspond
to the controller in a model-view-controller architecture because they
encapsulate the business logic of a three-tier architecture.

Two kinds of session bean:


Stateless Session Beans

Stateless session beans represent business processes
or tasks that are performed on behalf of the client using
them.

Stateless Session Bean Interfaces
// from EJB Fundamentals  by R. Monson-Haefel

// remote interface

     public interface CreditService extends javax.ejb.EJBObject {
              public void verify(CreditCard card, double amount)
                          throws RemoteException, CreditServiceException;

            public void charge(CreditCard card, double amount) 
                         throws RemoteException, CreditServiceException;
                         }
  // home interface

    public interface CreditServiceHome extends java.ejb.EJBHome {
             public CreditService create( )
                         throws RemoteException, CreateException;
                     } 
 
Stateless Session Beans Required No-args Create( ) Method

All home interfaces for stateless session beans will define
just one method, a no-argument create( ) method
. Session
beans do not have find methods and they cannot be initiated
with any arguments when they are created. Every client
that uses the same type of session bean gets the same
service.

CreditService Stateless Session Bean Sample
// from EJB Fundamentals  by R. Monson-Haefel

   import javax.ejb.SessionBean;

    public class CreditServiceBean implements SessionBean {
          URL acmeURL;
          HttpURLConnection acmeCon;

          public void ejbCreate( ) {
            try {
                  InitialContext jndiContext = new InitialContext( );
                  URL acmeURL = (URL) jndiContext.lookup("java:comp/ejb/env/url/acme");
                  acmeCon = acmeURL.openConnection( );
                  }
                 catch (Exception e) { throws new EJBException(e); }
          }

    public void verify(CreditCard card, double amount) 
          throws CreditCardException {
          String response = post("verify:" + card.postString( ) + ":" + amount);
              if (response.substring("approved") == -1 )
                                 throw new CreditServiceException("denied");
               }

    public void charge(CreditCard card, double amount) 
                  throws CreditCardException {
                  String response = post("charge:" + card.postString( ) + ":" + amount);
                  if (response.substring("approved")== -1)
                              throw new CreditServiceException("denied");
                         }

    private String post(String request) {
            try {
                   acmeCon.connect();
                   acmeCon.setRequestMethod("POST "+request);
                   String response = ameCon.getResponseMessage( );
                  }
                  catch (IOException ioe) {
                     throw new EJBException(ioe);
                    }
                }
   public void ejbRemove( ) {
                             acmeCon.disconnect( );
                             }

   public void setSessionContext(SessionContext cntx) {}
   public void ejbActivate() {}
   public void ejbPassivate() {}
   }

  
This bean encapsulates accesses the Acme secure web
server and posts requests to validate or charge the
customer's credit card. This example demonstrates the
stateless bean can represent a collection of independent
but related services.

Benefits of Connecting Through the Bean

By having the client connecting to the CreditService bean
instead of a connecting directly to the service the EJB
container is able to pool connections, manage transactions
and provide security automatically for the client.

In the example above, the CreditServiceBean uses the
ejbCreate( ) method to obtain a reference to the
HttpURLConnection factory, which it will use throughout
its lifetime to obtain connections to the Acme web server.

The CreditServiceBean uses the JNDI ENC to obtain a
URL connection factory in the same way that the
CustomerBean used the JNDI ENC to obtain a
DataSource resource factory for JDBC connections. 


Stub ejbActivate( ) & ejbPassivate( )


The ejbActivate( ) and ejbPassivate( ) methods are
not implemented because passivationis not used
in stateless session beans. However Because these
methods are defined in the SessionBean empty
implementations must be provided. 

 
Stateful Session Beans

Stateful session beans are dedicated to one client
and maintain 'conversational-state' between method
invocations. Unlike stateless session beans, clients do
not share
stateful beans. A stateful bean, is dedicated
to service only one client allowing business state to be
shared by methods in the same stateful bean.

As an example, the HotelClerk bean can be modified
to be a stateful bean which can maintain conversational
state between method invocations. This would be useful,
for example, to allow the HotelClerk bean to take many
reservations, but then process them together under one
credit card.

HotelClerkBean Modified to a Stateful Session Bean
// from EJB Fundamentals  by R. Monson-Haefel

import javax.ejb.SessionBean;
  import javax.naming.InitialContext;

   public class HotelClerkBean implements SessionBean {

      InitialContext jndiContext;
       //conversational-state
        Customer cust;
        Vector resVector = new Vector( );

       public void ejbCreate(Customer  customer) { }
         cust = customer;
         }

   public void addReservation(Name name, RoomInfo ri, Date from, Date to) {
       ReservationInfo resInfo = new ReservationInfo(name, ri , from, to);
       resVector.addElement(resInfo);
       }

   public void reserveRooms() {
        CreditCard card = cust.getCreditCard( );
        Enumeration resEnum = resVector.elements( );
            while (resEnum.hasMoreElements( )) {
               ReservationInfo resInfo = (ReservationInfo) resEnum.nextElement( );
               RoomHome roomHome = (RoomHome)
              getHome("java:comp/env/ejb/RoomEJB", RoomHome.class);
              Room room = roomHome.findByPrimaryKey(resInfo.roomInfo.getID( ) );
              double amount = room.getPrice(resInfo.from,restInfo.to);
              CreditServiceHome creditHome = (CreditServiceHome)getHome 
                 ("java:comp/env/ejb/CreditServiceEJB", CreditServiceHome.class);
              CreditService creditAgent = creditHome.create( );
              creditAgent.verify(card, amount);
              ReservationHome resHome = (ReservationHome)getHome 
              ("java:comp/env/ejb/ReservationEJB", ReservationHome.class);
              Reservation reservation = resHome.create 
              (cresInfo.getName( ), resInfo.roomInfo,resInfo.from,resInfo.to);
              }
              public RoomInfo[] availableRooms(Location loc, Date from, Date to){
              // Make an SQL call to find available rooms
              }
              private Object getHome(String path, Class type) {
                   Object ref = jndiContext.lookup(path);
                   return PortableRemoteObject.narrow(ref,type);
                   }
         }

In the stateful version of the HotelClerkBean class, the conversational
state
is maintained in the Customer reference which is obtained
when the bean is created
and also in the Vector of ReservationInfo
objects. The bean keeps track of the reservations and processes
them in a batch when the serverRooms( ) method is invoked.

Stateful Session Beans Usually Are Passivated Using Serialization

Stateful session beans may be passivated when they are not in use.
In stateful beans, passivation means the bean's conversational-state
is written to
a secondary storage (often disk) and the instance is
removed from memory. The client's reference to the bean is not affected
by passivation, it remains alive and usable while the bean is passivated.

When the client invokes a method on a passivated bean , the container
reactivates the bean by instantiating a new instance and restores
it's
conversational-state with data that had been written to secondary
storage
. This passivation/activation process is often accomplished using
simple Java serialization.  

Stateful session beans, unlike stateless beans, do use the ejbActivate( )
and ejbPassivate( ). Developers should use these method to close open
resources and to do other clean-up before the instance's state is written
to secondary storage and evicted from memory.

// The ejbRemove( ) method should do the same kind of clean-up
// performed in the ejbPassivate() method.


Deploying Enterprise JavaBeans

The EJB specification describes a declarative mechanism for
how the container handles persistence, transactions, concurrency,
and access control enterprise beans called the XML deployment
descriptor
.

When a bean is deployed into a container, the container reads
the deployment descriptor to find out how these functions should
be handled. The person deploying the bean will use this information
and specify additional information to hook the bean up to these
facilities at runtime.

A deployment descriptor has a predefined format that all EJB
compliant beans must use and all EJB compliant servers must
know how to read it. This format is specified in an XML Document
Type Definition
, or DTD.

The deployment descriptor describes the type of bean (session or
entity) and the classes used for the remote, home, and bean class.
It also specifies the transactional attributes of every method in the
bean, which security roles can access each method (access control),
and whether persistence in the entity beans is handled automatically
or is performed by the bean.

Example of an XML Deployment Descriptor for the Customer Bean
// from EJB Fundamentals  by R. Monson-Haefel

<?xml version="1.0"?>

   <!DOCTYPE ejb-jar PUBLIC "-  // Sun Microsystems, Inc. DTD Enterprise
          JavaBeans 1.1//EN"  "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">

         <ejb-jar>
              <enterprise-beans>
                   <entity>
                           <description> This bean represents a customer </description>
                           <ejb-name> CustomerBean  </ejb-name>
                           <home> CustomerHome </home>
                           <remote> Customer </remote>
                           <ejb-class> CustomerBean </ejb-class>
                           <persistence-type> Container </persistence-type>
                           <prim-key-class> Integer </prim-key-class>
                           <reentrant> False </reentrant>

                           <cmp-field><field-name> myAddress </field-name></cmp-field>
                           <cmp-field><field-name> myName </field-name></cmp-field>
                           <cmp-field><field-name> myCreditCard </field-name></cmp-field>
                    </entity>
              </enterprise-beans>

              <assembly-descriptor>
                  <security-role>
                           <description>
                          The role of who is allowed full access to the Customer bean.
                           </description>
                           <role-name> everyone </role-name>
                  </security-role>

             <method-permission>
                    <role-name> everyone </role-name>
                       <method>
                             <ejb-name> CustomerBean </ejb-name>
                             <method-name> * </method-name>
                       </method>
               </method-permission>

              <container-transaction>
                     <description> All methods require a transaction </description>
                          <method>
                              <ejb-name>CustomerBean</ejb-name>
                              <method-name>*</method-name>
                          </method>
                          <trans-attribute>Required</trans-attribute>
              </container-transaction>
          </assembly-descriptor>
       </ejb-jar>


EJB-capable application servers usually provide tools to build
deployment descriptors, greatly simplifying the process. When a
bean is deployed,
its remote, home, and bean class files and the
XML deployment descriptor must be packaged into a JAR file.


META-INF/ejb-jar.xml

The deployment descriptor must be stored under the META-INF
directory with the name, ejb-jar.xml
. This JAR file, called an ejb-jar,
is vendor neutral and can be deployed in any EJB compliant
container.  //  EAR archive file

When a bean is deployed in an EJB container it's XML deployment
descriptor is read from the JAR to determine how to manage the
bean at runtime. Deployment descriptor attributes are mapped to
the container's environment, including security  aspects,  adding
the bean to the EJB naming system etc. Successful deployment
makes the bean available to clients.
 

Enterprise JavaBeans Clients

Enterprise JavaBeans clients may be standalone applications,
servlets, applets, or even other enterprise beans. For instance,
the HotelClerk session bean shown above was a client of the
Room entity beans.

All clients use the server bean's home interface to obtain references
to the server bean. This reference has the server bean's remote
interface datatype, therefore the client interacts with the server
bean solely through the methods defined in the remote interface.

The remote interface defines the business methods, such as
accessor and mutator methods for changing a customer's name,
or business methods that perform tasks like using the HotelClerk
bean to reserve a room at a hotel.

Below is an example of how a Customer bean might be accessed
from a client application. In this case the home interface is
CustomerHome and the remote interface is Customer.


Example

// from EJB Fundamentals  by R. Monson-Haefel

     CustomerHome home;
      Object ref;  
       // Obtain a reference to the CustomerHome
      ref  = jndiContext.lookup("java:comp/env/ejb/Customer");
       // Cast object returned by the JNDI lookup to the appropriate datatype
      home = PortableRemoteObject.narrow(ref, CustomerHome.class);
     // Use the home interface to create a new instance of the Customer bean.
      Customer customer = home.create(customerID);
      // Use a business method on the Customer.

      customer.setName(someName);

A client first obtains a reference to the home interface by using
JNDI ENC to lookup the server beans. In EJB 1.1*, Java RMI-IIOP
is the specified programming model. As a consequence, all
CORBA references types must be supported. CORBA references
cannot be cast using Java native casting.

Instead the PortableRemoteObject.narrow( ) method must be used
to explicitly narrow a reference from one type to its subtype. Since
JNDI always returns an Object type, all bean references should be
explicitly narrowed to support portability between containers.

After the home interface is obtained, the client uses the methods
defined on the home interface to create, find, or remove the server
bean. Invoking one of the create() methods on the home interface
returns the client a remote reference to the server bean, which the
client uses to complete it's tasks.  

  // * need an update for EJB 2.x


Assignment


 
EJBs are at the heart of the J2EE specification. They are complex
and programming them via an IDE like Eclipse or RAD7 only further
obscure their anatomy and inner workings.

Please read over this note this week. This will provide a good
background for the approach we see in the more recent take on
EJBs we see taken in J2EE Eclipse and RAD7.