EntityContext

The first method called by the container after a bean instance is created is setEntityContext( ). This method passes the bean instance a reference to its javax.ejb.EntityContext, which is really the instance’s interface to the container.

The setEntityContext( ) method should be implemented by the entity bean developer so that it places the EntityContext reference in an instance field of the bean where it will be kept for the life of the instance. The definition of EntityContext is as follows:

public interface javax.ejb.EntityContext extends javax.ejb.EJBContext {
    public EJBLocalObject getEJBLocalObject( ) throws IllegalStateException
    public abstract EJBObject getEJBObject( ) throws IllegalStateException;
    public abstract Object getPrimaryKey( ) throws IllegalStateException;
}

As the bean instance is swapped from one EJB object to the next, the information obtainable from the EntityContext changes to reflect the EJB object to which the instance is assigned. This change is possible because the EntityContext is an interface, not a static class definition, so the container can implement the EntityContext with a concrete class that it controls. As the entity bean instance is swapped from one EJB object to another, the information made available through the EntityContext will also change.

The EntityContext.getEJBObject( ) method returns a remote reference to the bean instance’s EJB object. The EntityContext.getEJBLocalObject( ) method, on the other hand, returns a local reference to the bean instance’s EJB object.

Session beans also define the getEJBObject( ) and getEJBLocalObject( ) methods in the SessionContext interface; their behavior is exactly the same.

The EJB objects obtained from the EntityContext are the same kinds of references that might be used by an application client, in the case of a remote reference, or another co-located bean, in the case of a local reference. The getEJBObject( ) and getEJBLocalObject( ) methods allow the bean instance to get its own EJB object reference, which it can then pass to other beans. Here is an example:

public class A_Bean extends EntityBean {
    public EntityContext context;
    public void someMethod( ) {
        B_BeanRemote  b = ... // Get a remote reference to B_Bean.
        EJBObject obj = context.getEJBObject( );             
        A_BeanRemote mySelf =  (A_BeanRemote)
             PortableRemoteObject.narrow(obj,A_BeanRemote.class);
        b.aMethod( mySelf );
    }
    ...
          }

It is illegal for a bean instance to pass a this reference to another bean; instead, it passes its remote or local EJB object reference, which the bean instance gets from its EntityContext.

The ability of a bean to obtain an EJB object reference to itself is also useful when establishing relationships with other beans in container-managed persistence. For example, the Customer EJB might implement a business method that allows it to assign itself a Reservation:

public abstract class CustomerBean implements javax.ejb.EntityBean {
    public EntityContext context;

    public void assignToReservation(ReservationLocal reservation) {
        EJBLocalObject localRef = context.getEJBLocalObject( );
               Collection customers = reservation.getCustomers( );
        customers.add(localRef);
    }
    ...
}

The EntityContext.getPrimaryKey( ) method allows a bean instance to get a copy of the primary key to which it is currently assigned. Use of this method outside of the ejbLoad( ) and ejbStore( ) methods of BMP entity beans is unusual, but the EntityContext makes the primary key available for those unusual circumstances when it is needed.

As the context in which the bean instance operates changes, some of the information made available through the EntityContext reference will be changed by the container. This is why the methods in the EntityContext throw the java.lang.IllegalStateException. The EntityContext is always available to the bean instance, but the instance is not always assigned to an EJB object. When the bean is between EJB objects (i.e., when it’s in the pool), it has no EJB object or primary key to return. If the getEJBObject( ), getEJBLocalObject( ), or getPrimaryKey( ) methods are invoked when the bean is in the pool, they will throw an IllegalStateException. Appendix B provides tables of allowed operations for each bean type describing which EJBContext methods can be invoked at what times.

EJBContext

The EntityContext extends the javax.ejb.EJBContext class, which is also the base class for the SessionContext session beans use. EJBContext defines several methods that provide useful information to a bean at runtime.

Here is the definition of the EJBContext interface:

package javax.ejb;
public interface EJBContext {

    // EJB 2.1 only: TimerService
    public TimerService getTimerService( )
       throws java.lang.IllegalStateException;

    // EJB home methods
    public EJBHome getEJBHome( )
       java.lang.IllegalStateException;
    public EJBLocalHome getEJBLocalHome( )
       java.lang.IllegalStateException;
   
    // security methods
    public java.security.Principal getCallerPrincipal( );
    public boolean isCallerInRole(java.lang.String roleName);
   
    // transaction methods
    public javax.transaction.UserTransaction getUserTransaction( ) 
        throws java.lang.IllegalStateException;
    public boolean getRollbackOnly( ) 
        throws java.lang.IllegalStateException;
    public void setRollbackOnly( ) 
        throws java.lang.IllegalStateException;

    // deprecated methods
    public java.security.Identity getCallerIdentity( );
    public boolean isCallerInRole(java.security.Identity role); 
    public java.util.Properties getEnvironment( );

}

The EJBContext.getTimerService( ) method (EJB 2.1 only) returns a reference to the container’s Time Service, which allows the entity to set up notifications for itself of timed events. In other words, an entity can set alarms so that the container will call it when a specific date arrives, or some interval of time has passed. For example, an entity bean might set a timer as follows:

public class CustomerBean implements EntityBean, TimedObject {
    EntityContext ejbContext;
    ...
    public void scheduleAppointment(Date date, String description){
         TimerService timerService = ejbContext.getTimerServcie( );
         timerService.createTimer( date, description );
   }
   public void ejbTimeout(Timer timer){
       // do something when the timer goes off
   }
  ...
}

The scheduleAppointment( ) method is a business method that’s made available to remote clients via the remote interface. A client can call this method passing in a date and description of an event, which are in turn used to create a timer; to register the entity for a timed event. In order for an entity to be notified of a timed event it must implement the javax.ejb.TimedObject interface, which defines one method: ejbTimeout( ). When the date of a timed event arrives, the Timer Service, which is part of the EJB container, will call the ejbTimeout( ) method. The entity can get details of the timed event from the javax.ejb.Timer object, including the description. The Timer Service is covered in detail in Chapter 13.

The EJBContext.getEJBHome( ) and EJBContext.getEJBLocalHome( ) methods return a reference to the bean’s EJB home. This is useful if the bean needs to create or find entity beans of its own type. Access to the EJB home may be more useful in BMP entity beans than in CMP entity beans, which have select methods and CMR fields.

As an example, if all of the employees in Titan’s system (including managers) are represented by BMP Employee beans, a manager who needs access to subordinate employees can use the getEJBLocalHome( ) method to get beans representing the appropriate employees:

public class EmployeeBean implements EntityBean {
    EntityContext ejbContext;
    ...
    public EmployeeLocal createSubordinate( ) {            
        EmployeeLocal mySelf = (EmployeeLocal)ejbContext.getEJBLocalObject( );
        EmployeeHomeLocal home = (EmployeeHomeLocal)ejbContext.getEJBLocalHome( );
        EmployeeLocal subordinate = home.createSubordinateTo( mySelf );
        return subordinate;
    }
    ...
}

The EJBContext.getCallerPrincipal( ) method is used to obtain the java.security.Principal object representing the client that is currently accessing the bean. The Principal object can, for example, be used by the BMP Ship EJB to track the identities of clients making updates:

public class ShipBean implements EntityBean {
    String lastModifiedBy;
    EntityContext context;
    ...
    public void setTonnage(double tons) {
        tonnage = tons;
        Principal principal = context.getCallerPrincipal( );
        String modifiedBy = principal.getName( );
        ...
    }
    ...
}

The EJBContext.isCallerInRole( ) method tells you whether the client accessing the bean is a member of a specific role, identified by a role name. This method is useful when more access control is needed than simple method-based access control can provide. In a banking system, for example, you might allow the Teller role to make most withdrawals but only the Manager role to make withdrawals of over $10,000. This kind of fine-grained access control cannot be addressed through EJB’s security attributes because it involves a business logic problem. Therefore, we can use the isCallerInRole( ) method to augment the automatic access control provided by EJB. First, let’s assume that all managers are also tellers. The business logic in the withdraw( ) method uses isCallerInRole( ) to make sure that only the Manager role can withdraw sums over $10,000.00:

public class AccountBean implements EntityBean {
    int id;
    double balance;
    EntityContext context;

    public void withdraw(Double withdraw) throws AccessDeniedException {
        
        if (withdraw.doubleValue( ) > 10000) {
            boolean isManager = context.isCallerInRole("Manager");
            if (!isManager) {
                // Only Managers can withdraw more than 10k.
                throw new AccessDeniedException( );
            }
        }
        balance = balance - withdraw.doubleValue( );

    }
    ...
}

The EJBContext contains some methods that were used in EJB 1.0 but were deprecated in EJB 1.1 and have been abandoned in EJB 2.0 and EJB 2.1. Support for these deprecated methods were optional for EJB 2.0 containers, they are not supported by EJB 2.1. EJB containers that do not support the deprecated security methods will throw a RuntimeException. The deprecated security methods are based on EJB 1.0’s use of the Identity object instead of the Principal object. The semantics of the deprecated methods are basically the same but, because Identity is an abstract class, it has proven to be too difficult to use. Even if your EJB 2.0 vendor supports these deprecated methods, you should never use them for new entity beans. They should only be used if you are continuing to support legacy EJB 1.0 entities—a fairly rare occurence.

The getEnvironment( ) method has been replaced by the JNDI environment naming context, which is discussed later in this book. EJB 2.0 containers may optionally support this method for backward compatibly with legacy EJB 1.0 components, but EJB 2.1 containers do not support this method at all and will throw a RuntimeException if its called. The transactional methods—getUserTransaction( ), setRollbackOnly( ), and getRollbackOnly( )—are described in detail in Chapter 15.

The material on the EJBContext covered in this section applies equally well to session and message-driven beans. There are some exceptions, however, and these differences are covered in Chapter 11 and Chapter 12.

JNDI ENC

Starting with EJB 1.1, the bean-container contract for entity and stateful beans was expanded beyond the EJBContext using the Java Naming and Directory Interface ( JNDI). A special JNDI name space, which is referred to as the environment naming context (ENC), was added to allow any enterprise bean to access environment entries, other beans, and resources (such as JDBC DataSource objects) specific to that enterprise bean.

The JNDI ENC continues to be an extremely important part of the bean-container contract. Although we used the JNDI ENC to access JDBC in the bean-managed persistence chapter (Chapter 9), it’s not specific to entity beans. The JNDI ENC is used by session, entity, and message-driven beans alike. To avoid unnecessary duplication, a detailed discussion of this important facility is left for Chapter 11. What you learn about using the JNDI ENC in Chapter 11 applies equally well to session, entity, and message-driven beans.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.107.25