Using the primary key of the containing entity to hold Handles of related entity beans.

ARCHITECT'S CORNER
Entity bean relationships in EJB 1.1
Grant Holland
Listing 2. Using the primary key of the containing entity to hold Handles of related entity beans.

This example demonstrates how to store related key fields in the primary key object of the containing entity. The related key fields are stored as Handles. The example presents the pertinent parts of the code for the LineItem entity bean implementation.

The primary key class, LineItemPK, is presented in its entirety. Notice that we have declared the Handle of the Product EJBObject (productHandle field) as a field of the LineItemPk class in order to hold it during passivation.

Notice that there are two types of fields in the primary key class: identifying fields and relationship fields. Notice also that the toString(), equals() and hashCode() methods are overridden.


public class LineItemPK implements java.io.Serializable
{
    public	int 		lineItemID;	     // identifying field
    public	int 		orderID;            // identifying field
    public	Handle	productHandle;  // relationship field

    // Override toString() to use only the identifying fields.
    public String toString()
    {
     return String.valueOf(orderID) + “+”
					+ String.valueOf(lineItemID);
    }

    // Override equals() to use only the identifying fields.
    public boolean equals( Object other )
    {
        if( other == null )
            return false;
        if( !(other instanceof LineItemPK ) )
            return false;

        if(  (((LineItemPK)other).lineItemID == lineItemID) &&
	          (((LineItemPK)other).orderID == orderID)	   )
            return true;
        else
            return false;
    }

    // Override hashCode()to use only the identifying fields.
    public int hashCode()
    {
        return lineItemID;
    }
}
For the LineItem entity bean implementation, the example will implement the code for a business method (getCost), ejbCreate, ejbFindByPrimaryKey and ejbActivate. ejbLoad, ejbStore, and other callbacks will not be shown in this example.

ejbCreate() first captures the identifying persistent data and the related EJB object from the parameter list. Then it writes the persistent fields to the database. (Notice that it also writes related key fields to the database. This if for use by ejbFind when instantiating a new instance of the entity.) Then ejbCreate calculates the Handle of the EJBObject, which it will use as its related key. After persisting what it needs to, it then creates a primary key object, inserts both the identifying field (lineItemID and orderID) and the relationship field (productHandle) into it, and returns the primary key object to the container. Notice that it obtains the Handle by invoking the getHandle method on the EJBObject.


package ejbrelationships.lineitem;

import javax.ejb.*;
import java.rmi.RemoteException;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import java.io.*;
import ejbrelationships.product.*;

public class LineItemEJB implements EntityBean
{
  EntityContext ctx;

  public int 		    lineItemID;		   // persistent data
  public int 		    orderID;		  // persistent data
  public int 		    quantity;		  // persistent data
  public String		productName;	 // persistent data
  public Product 	product;		// related EJB object

  public float getCost() throws RemoteException
  {
		// Invoke a biz method on the related Product entity bean
    return quantity * product.getPrice();
  }

  public LineItemPK ejbCreate(
		int 			lineItemID,   // identity field
		int 			orderID,      // identity field
		int 			quantity,    // persistent field
		Product 	product	 // related EJBObject
											)
	            throws CreateException,RemoteException
  {

    LineItemPK pk;

    try
    {
		// capture all field types
		this.lineItemID = lineItemID;		// persistent data
		this.orderID = orderID;		   // persistent data
		this.quantity = quantity;		  // persistent data
		this.productName = 		      // related key
			((ProductPK)product.getPrimaryKey()).productName;
		this.product = product;		// related EJB obj

	/*
		// persist persistent data
		< write “lineItemID” 	to persistent store >
		< write “orederID” 	to persistent store >
		< write “quantity”   	to persistent store >
	
		// Serialize the Handle and write it to persistent store
		// - ONLY NECESSARY FOR FINDERS on subsequent sessions
	    byte[] productSerHandle = serialize(product.getHandle( ));
		< write productSerHandle to persistent store >
		*/

		// create and initialize Primary Key object
		pk = new LineItemPK(); 			// make PK
		pk.orderID = orderID;			// capture identity field
		pk.lineItemID = lineItemID;		// capture identity field

	       // CAPTURE RELATIONSHIP HANDLE IN PRIMARY KEY OBJECT!
		pk.productHandle = (Handle)product.getHandle();
    }
    catch(Exception e)
    {
	    throw new CreateException(e.getMessage());
    }

    return pk;
  }

  // Before passing it as the parameter to this method, the client
  // will initialize the primary key object with identifying fields.
  // Client may set the related entity Handle to null,
  // if it is unknown to him.
  // If so, this method will read the serialized Handle
  // from persistent store, as placed there by ejbCreate,
  // and put it into the primary key object.
  // The primary key object will be returned.
  public LineItemPK findByPrimaryKey( LineItemPK pk )
  {
      // PK as received may only be initialized with
      // orderID and lineItemID – and not with productHandle.
      // productHandle can be set to <null> by client
      // if unknown to him.
	// If so, we must read and deserialize productHandle from
	// persistent store and set it into the PK
// before returning it.

	if(pk.productHandle == null )
      {
         // If so, orderID and lineItemID must be used
         // to locate state for this entity on persistent store.

         < Read any persistent data from persistent store into
  	         into resultSet, including the serialized Product Handle,
  	         which was persisted there by ejbCreate.                    >

         // get serialized Product Handle from the result set.
         byte[]productSerHandle
                 = resultSet.getByteArray(“productserhandle”);

         // deserialize Handle and put it into the primary key
         pk.productHandle = deserialize(productSerHandle);
      }

      return pk;
  }

  public void ejbActivate() throws RemoteException
  {
       // Obtain primary key from entity context
      LineItemPK pk = (LineItemPK) ctx.getPrimaryKey();

      try
      {
	         // THIS IS THE POINT OF THE REFINED TECHNIQUE
	         // reconstitute related EJB object from primary key
    	    Handle productHndl =
                  ((LineItemPK)ctx.getPrimaryKey()).productHandle;
    	    product = (Product)productHndl.getEJBObject();
	}
	catch(Exception e)
	{
	         throw new RemoteException(e.getMessage());
	}
   }
}