Skip Headers

Oracle9iAS TopLink CMP for Users of IBM WebSphere Guide
Release 2 (9.0.3)

Part Number B10067-01
Go To Documentation Library
Home
Go To Solution Area
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Go to previous page Go to next page

6
Run time considerations

This chapter discusses some of the relevant run-time issues surrounding writing an application that uses TopLink Container-Managed Persistence in the IBM WebSphere Server container. Other facets of the run-time execution that relate to EJB's and the IBM WebSphere Server are beyond the scope of this document and should be reviewed in the EJB specification and/or the IBM WebSphere Server documentation.

Transaction support

Entity beans that use container-managed persistence may participate in transactions that are either client-demarcated or container-demarcated.

Clients of entity beans may directly set up transaction boundaries using the javax.transaction.UserTransaction interface. Invocations on entity beans are automatically wrapped in transactions that are initiated by the container based upon the transaction attributes supplied in the EJB deployment descriptor.

For more information on how to use transactions with EJBs, consult the EJB specification and the IBM WebSphere Server documentation. The following sections describe briefly how TopLink participates in EJB transactions.

TopLink within the IBM WebSphere Server

Within the IBM WebSphere Server, TopLink provides a persistence layer for entity beans. While the IBM WebSphere Server controls all aspects of transaction management, the TopLink layer is synchronized with the IBM WebSphere transaction service so that updates to the database are carried out at the appropriate times.

When updates occur

In general, TopLink does not issue updates to the underlying data store until the transaction that the enterprise beans are active in begins its two-stage commit process. This allows for:

Valid transactional states

All modifications to persistent beans and objects should be carried out in the context of a transaction. The transaction may either be client-controlled or container-controlled.

The TopLink container does not support modifying beans through their remote interface when no transaction is active. In this case, TopLink does not write out any changes to the data. Modifying entity beans without a transaction leads to an inconsistent state, potentially corrupting the values in the TopLink cache. Transactional attributes MUST be properly specified in the bean deployment descriptors, to ensure that data is not corrupted.

Although it is not valid to modify entity beans through their remote interface without a transaction, in the current release it is permitted to invoke methods on EJB homes that change the state in the underlying database. Invocation of removes and creates that are invoked against homes in the absence of a transaction are permitted.

The following table shows various combinations of container transaction attributes and client transaction behavior. For each case, it is shown whether or not a transaction will be active. For those situations that read "no transaction is active," no modifications to entity beans should be carried out.

Table 6-1 Container transaction behavior as a function of transaction attribute and UserTransaction existence  
Transaction attribute Client transaction exists No client transaction exists

NotSupported

No transaction is active

No transaction is active

Supports

Transaction is active

No transaction is active

Required

Transaction is active

Transaction is active

RequiresNew

Transaction is active

Transaction is active

Mandatory

Transaction is active

Exception is raised

Never

Exception is raised

No transaction is active

Situations described above for which "no transaction is active" should be avoided if entities are to be modified. Bean developers should be particularly careful of using the Supports transaction attribute, because it leads to a non-transactional state whenever the client does not explicitly provide a transaction.

Maintaining bidirectional relationships

When one-to-many or many-to-many mappings are bi-directional then the back-pointers must be correctly maintained as the relationships change. When the relationship is between an entity bean and a Java object, or when the application is built to the EJB 1.1 specification (as is the case when using IBM WebSphere Application Server), the relationship must be maintained manually.

One-to-Many relationship

In a one-to-many mapping, an EmployeeBean might have a number of dependent phoneNumbers. When a phoneNumber is added to an employee record, the phoneNumber's back-pointer to its owner (the employee) must also be set.

Example 6-1 Setting the back-pointer in the entity bean

Maintaining a one-to-many relationship in the entity bean involves getting the local object reference from the context of the EmployeeBean, then updating the back-pointer. The following code illustrates this technique:

// obtain owner and phoneNumber
owner = empHome.findByPrimaryKey(ownerId);
phoneNumber = new PhoneNumber("cell", "613", "5551212");
// add phoneNumber to the phoneNumbers of the owner
owner.addPhoneNumber(phoneNumber);

The Employee's addPhoneNumber() method maintains the relationship as follows:

public void addPhoneNumber(PhoneNumber newPhoneNumber) {
   //get, then set the back pointer to the owner
   Employee owner = (Employee)this.getEntityContext()
   .getEJBLocalObject();
   newPhoneNumber.setOwner(owner);
   //add new phone
   getPhoneNumbers().add(newPhoneNumber);
}

Managing dependent objects

The EJB 1.1 specification recommends that entity beans be modeled such that all dependent objects are regular Java objects and not entity beans. If a dependent or privately owned object is to be exposed to the client application it must be serializable (it must implement the java.io.Serializable interface) so that it may be sent over to the client and back to the server.

Serializing Java objects between client and server

Recall that entity beans are remote objects. This results in a "pass-by-reference" situation when entity beans are referenced remotely. When an entity bean is returned to the client, a remote reference to the bean is returned.

Regular Java objects are not remote objects like entity beans are. Instead of a "pass-by-reference" situation, when regular Java objects are referenced remotely they are "passed-by-value" and serialized (copied) from the remote machine that they were originally on.

Managing collections of EJBObjects

Collections typically use the equals() method to compare objects. However, in the case of a Java object that contains a collection of entities, the EJBObjects do not respond as expected to the equals() method. In this case, the isIdentical() method should be used instead. Consequently, you cannot expect the standard collection methods such as remove() or contains() to work properly when applied to a collection of EJBObjects.


Note:

This issue does not arise in the case of an entity containing a collection of entities, because a special EJB 2.0 container collection is used which handles equality appropriately.


Several options are available when dealing with collections of EJBObjects. One option is to create a helper class to assist with collection-type operations. An example of such a helper is provided in the distribution named EJBCollectionHelper:

public void removeOwner(Employee previousOwner){
   EJBCollectionHelper.remove(previousOwner, getOwners());
}

The implementation of remove() and indexOf() in EJBCollectionHelper is shown in the next example:

public static boolean remove(javax.ejb.EJBObject ejbObject, Vector vector) {
   int index = -1;
   index = indexOf(ejbObject, vector);
   // indexOf returns -1 if the element is not found.
   if(index == -1) {
      return false;
   }
   try {
      vector.removeElementAt(index);
   } catch(ArrayIndexOutOfBoundsException badIndex) {
      return false;
   }
   return true;
}

public static int indexOf(javax.ejb.EJBObject ejbObject, Vector vector) {
   Enumeration elements = vector.elements();
   boolean found = false;
   int index = 0;
   javax.ejb.EJBObject current = null;
   while(elements.hasMoreElements()) {
      try {
         current = (javax.ejb.EJBObject)
         elements.nextElement();
         if(ejbObject.isIdentical(current)) {
            found = true;
            break;
         }
      } catch(ClassCastException wrongTypeOfElement) {
         . . .
      } catch (java.rmi.RemoteException otherError) {
         . . .
      }
      index++; //increment index counter
   }
   if(found) {
      return index;
   } else {
      return -1;
   }
}

If JDK 1.2 is used, a special Collection class could be created that uses isIdentical() instead of equals() for all its comparison operations. For isIdentical() to function correctly, the equals() method must be properly defined for the primary key class.


Go to previous page Go to next page
Oracle
Copyright © 2002 Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Solution Area
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index