Oracle9iAS TopLink CMP for Users of IBM WebSphere Guide Release 2 (9.0.3) Part Number B10067-01 |
|
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.
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.
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.
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:
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.
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.
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.
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.
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); }
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.
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.
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
.
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.
|
Copyright © 2002 Oracle Corporation. All Rights Reserved. |
|