Chapter 20: Entity Beans and Persistence
Download
Report
Transcript Chapter 20: Entity Beans and Persistence
Entity Beans and Persistence
• Entity Enterprise JavaBeans REPRESENT
entity objects in an analysis model
– Real World Concepts
• Customers
• Products
– Abstractions
• Process
• Customer Purchases
Representation
• Session Beans
– Can access the data that Entity Beans can
access
– Cannot provide an object-oriented
representation of that data
• WHY?
– Why can't you have a 'customer' or 'product'
session bean, like you can with entity beans?
The Problem of State
• Entity Beans
– State is SHARED, TRANSACTIONAL
• Session Beans
– State is PRIVATE, CONVERSATIONAL
• Problem:
– If attempting to use a Session Bean to represent
an object, how is the STATE made available to
clients of the that bean?
Transactions
• Atomic
•
More details,
– Success of failure as a group see Chapter 21,
page 1031
Consistent
– Database state not compromised by success or
failure
• Isolated
– System activities isolated from each other
• Durable
– A committed transactions is reflected in the
store
Transactional State
• "Roughly speaking, transactional state is the
data you store in the persistent store.
Multiple clients can read and modify this
data without conflict. If the application
server crashes or is restarted, the data is still
available in the data store." (p. 909)
Conversational State
• "Conversational state is the data cached in
the application variables, either on the client
or the server. This is private data that isn't
accessible by other clients. If the
conversational state isn't turned into
transactional state, it can disappear when a
component of the application disappears"
(p. 909)
Beans, Beans, Everywhere
• Entity Bean
– Logically a single point of access for data -any client will access the data through the entity
bean
• Session Bean
– Can only be accessed by a single client -multiple clients will require multiple session
beans
Goals
• Compare and Contrast using an entity bean
and a session bean
• Compare and contrast entity beans whose
persistence mechanism is container
managed and those whose are managed by
the bean developer (bean managed)
Session Beans -- Why not?
• How might we try to get a session bean to
play the same role as an entity bean?
• In other words, let's try to build an entity
bean out of session bean parts.
• Let's create a bean that is intended to
provide an O-O representation of a
particular customer -- data will be accessed
as properties of the Customer object
» Code snippet, see p. 968 of text.
Stateful Session Bean
public class Customer implements SessionBean{
public int customerID;
public String customerName
The session bean's
public String customerAddr;
state
public String city
public String state;
public String postalCode;
public void ejbCreate(String customerID){
this.customerID = customerID;
}
public void setCustomerName(String customerName){
this.customerName = customerName;
}
// .. . . Similar Methods . . .
public void saveStateToDatabase(){
// . . . SQL Code . . .
}
public void loadStateFromDatabase(){
// . . . SQL Code
}
// . . . Lifecycle methods . . .
}
Using Stateful Session Beans
• What is the sessions bean's state?
– The customer data for a particular customer
• name, address, etc.
• The state is loaded from the database by one
method
• The state is saved to the database by another
method
Isn't This Approach Gonna Be
Messy??
• Problem
– When do methods for loading and saving the
state to the database get called?
– Is the client code to have calls to these methods,
like bookends around the business logic?
» Less than desireable!!
• Solution
eNTiTy bEanZ!!
– Entity Beans, of course.
• EBs have special callbacks that help the container
manage their state automatically
Not so fast, Bucko!!!
• Session beans can duplicate these special
container-managed-state callbacks by
implementing
– javax.ejb.SessionSynchronization
» Tell me more!
SessionSynchronization Interface
• Provides to Session Beans optional
callbacks that the container will use to
notify the bean . . .
• When the transaction begins
• When the transation is about end
• These transation boundaries are the place to
synchronize object state with the database!
• A little code, please . . .
» (see page 969)
public class Customer implements SessionBean,
SessionSynchronization{
// . . .
public void afterBegin() {
loadStateFromDatabase(); // EXCELLENT!!
}
public void afterCompletion(boolean commit) {
// if commit is false, ROLL BACK
}
public void beforeCompletion() {
// called only if no roll back
saveStateToDatabase(); // EXCELLENT!!
}
}
• As you can see . . .
– The bean is notified by the container that the
transaction has begun, and then the bean can
call loadStateFromDatabase()
– Similarly, when the transaction is about to end,
the container notifies the bean, and then the
bean can call saveStateToDatabase()
SESSION BEANS ALL THE
WAY!!
• It looks like Session Beans provide us will
all the functionality we need . . .
• We can handle STATE -- NO problem.
» Err, excuse me . . .
Let the chanting begin . . .
SESSION BEANS!!
SESSION BEANS!!
SESSION BEANS!!
The crowd goes wild!!
In Case You Forgot...
• . . . this "perfectly adequate" representation
of a customer entity using only a SESSION
BEAN . . .
– IT AINT SO ADEQUATE!!!
• CUZ
– This SB represents the state of a single client
only -- HELLO!?!?!?!
» Ooops!!
Whaaat… How… ?? I'm So
Confused!
• What's Missing?
• Understanding of . . .
– the limitation of using "private, conversational
state to represent shared data"
• Consider the Case . . .
– in which we have two session beans within one
transaction that need to access customer data
Let's Process an Order!!
• We need to change the . . .
– customer's ship-to address
– the customer's available credit
• These activities will be performed by two
stateless session beans called . . .
– "manage preferences"
– "manage acounts"
As a part of their work, both
beans must . . .
• Alter data managed by the Customer object
• Create a stateful session bean to represent
the customer, using the create() method
to associate the customer ID with the bean
• Invoke the appropriate business method
• setCustomerPreferences(CustomerPref
erencesView preferences)
• setAvailableCredit(double
availableCredit)
As the business methods are
invoked . . .
• Each Customer bean is enlisted into the
transaction
• afterBegin() is called on each bean
– the state data is loaded
– GULP!! We now have two (count 'em, TWO)
copies of the same state data. Each copy is
accessible only by its client.
» I have a feeling this isn't going to be good
First Dilemma
• What do we do with the Customer beans?
• Remember
– They have state, and are consuming resources .
..
Possible Solutions That Turn Out
to be STUPID
• Remove the Bean!!
– illegal
– stateful sessions beans cannot be removed in
the middle of a transaction
• Have Application Server Remove the
Bean!!
– Requires a time-out -- performance problems
Contrast with EJBs
• EJBs are Shared Objects
– the instantiation and destruction are handled
directly by the container
– as the entity beans don't belong to any one
client, the client is not responsible for removing
them from the container
• Life Cycle Methods
– EJBs
• refer to the underlying storage mechanism (like a
database)
– SBs
• refer to the EJB in the container
Other Problems
• Using Stateful session beans to represent a
Customer objects has two other problems
• Because SBs represent private,
conversational data, and not shared
transactional data -– copies of data can become unsynchronized
– copies can become stale
Inconsistent State Results
• When the transaction is about to commit
– container calls beforeCompletion() on
the two customer beans (undefined order)
– the first updates the data in the database . . .
– when the second performs its update . . .
» the database will be left in an inconsistent state!
Contrast with EJB
• EJBs are SHARED objects
– As far as clients are concerned
• there is only ONE bean which they are all accessing
– the changes from one client in a transaction . . .
• will be reflected in an access by a different client
– . . . therefore, kept in a consistent state
How About Using a Stateless
SB?
• Stateless SB? Couple of Issues
– SB being reference by the client, cannot be
associated with an identity (e.g., primary
key), BECAUSE it cannot remember that
identity from method call to method call
• SO, we'd have to pass the identity to each method
– No ability to cache
• SO, any information needed must be read in, and
any updates must be written immediately. EVERY
method that accesses state must do this.
Code Follows
• Taking the previous two points into
consideration . . .
» see page 971ff
public class Customer implements SessionBean{
public void setCustomerName(String customerID, String
customerName){
Connection con = null;
try {
con = getConnection();
PreparedStatement statement =
con.prepareStatement("Update…");
statement.setString(1,customerName);
statement.setString(2, customerID);
int updated = statement.executeUpdate();
if (updated != 1){
throw new EJBException("Customer not
found.");
}
} catch (SQLException sqle) {
throw new EJBException(sqle);
}
finally {
try {
if (con != null) {
con.close();
}
}catch (Exception e) {}
}
}
public String getCustomerName(String customerID){
Connection con = null;
try {
con = getConnection();
PreparedStatement statement =
con.prepareStatement("SELECT Name FROM
Customer
WHERE id=?");
statement.setString(1, customerID);
ResultSet resultSet = statement.executeQuery();
if (!resultSet.next()) {
throw new EJBException("Customer not
found.");
}
return resultSet.getString(1);
} catch (SQLException sqle) {
throw new EJBException(sqle);
}
finally {
try {
if (con != null){
con.close();
}
}catch (Exception e) ()
}
}
// . . .
}
This code has none of the fatal
flaws of the stateful version
• The client does not need to worry about the
removal of the SB
– Calling remove() does not produce an error
• Since each operation on a stateless session bean is
automatic
• Data cannot become unsynchronized and
inconsistent
– no private caches
– database can manage concurrent accesses
So, Then . . . EJBs Obsolete?
• Notice that this code is "painful"
– Embedding SQL directly in your Java is tedious
and error prone.
• This approach is not providing an O-O view
of your data
– really it's just providing a function library
– the stateless session customer bean has only
functionality; it does NOT have data, nor
identity
Benefits of EJBs
• Container callbacks to manage caching
within a transaction
• Support for concurrent access
• Maintaining a cache between transactions
• Providing all the persistence management
code
» WOW!! Cool!!
Container vs Bean Managed
Persistence
• The EJB container can manage the process
of saving and restoring the state of your
entity beans
» This is known as CMP, contain-managed
persistence
• The bean developer can control the bean's
persistence
» This is known as BMP, bean-managed persistence
Container vs Bean Managed
Persistence
• Deciding on WHICH form of persistence . .
.
– CMP
– BMP
• . . . is one of the most important
implementation decisions
» What is clear is that persistence is NOT
appropriate for business logic programmers
Container vs Bean Managed
Persistence
• SQL Code?
– Moving the state of the Java object back and
forth from a database?
•
•
•
•
This is a common manifestation of persistence
Time consuming
Tedious
ERROR prone
Container vs Bean Managed
Persistence
• EJB Framework . . .
– Moves persistence issues to the EJB container
• So!
– CMP must be the way to GO!!
» Well not always . . .
Container vs Bean Managed
Persistence
• Although every EJB-1.1 compliant
container MUST provide CMP . . .
– the specification does not indicate HOW this
support is to be provided
• The fact is that . . .
– The container need not provide ANY support
for mapping your entity bean's state to columns
in a database
– It COULD use Java serialization to write the
whole bean state to one column and still be
complient!
» Gee, that's not what I wanted . . .
Container vs Bean Managed
Persistence
• BUT . . .
– Such theoretical cases don't exist in REAL
LIFE
– According to your author, "Every single
application server with EJB support of which I
am away . . . has some support for mapping
your objects to the fields in a relational
database" (974)
• STILL . . .
– You MUST determine whether the EJB
container has the level of CMP support YOU
need
– If it does, use it
» Like, DUH!! the boost in productivity is potentially
very large, as well as, perhaps, application
performance!
Container vs Bean Managed
Persistence
• Please note:
– EJB 2.0 containers can be depended on to
manage mappings between multiple tables and
entity relationships
– It may be that even the portion of the container
responsible for performing these mappings (the
persistence manager) will be portable across
EJB 2.0 containers
Container vs Bean Managed
Persistence
• If you MUST use BMP . . .
– Seek THEARPY and use PROZAC
– Trying finding another container!
» Even after reading this chapter!!
– Use a third-party object/relational mapping tool
– Change your design
– Write you own data-access code
SportsBean Lab
• See page 975-978
• A simple application that allows us to talk
about persistence using either CMP or BMP
» Take a look for details -- most of them ought to
become apparent as we discuss the callbacks, etc.
C.R.U.D. Callbacks
•
•
•
•
Create
Read
Update
Delete
Create
• When a client calls create() for an
entity bean . . .
– state data is inserted into the corresponding data
store
• this is transactional data that is accessible from
multiple clients
• When a client calls create() for a
stateful SB
– the EJB container creates a private, nontransactional store of data in the applications
server's temporary storeage
Create
"When you call create() on a session
bean's home interface, you are creating an
instance of that session bean, whereas when
you call create() on an entity bean's
home interface, you are actually inserting a
record in the database." (979)
Create()
• There can be multiple forms of create()
defined in the bean's home interface
– These methods may take different parameters, which
correspond to the bean's state at time of creation
– The parameters must have enough information to initialize
the primary key of the entity
• ALL create methods MUST
– return the bean's remote interface
» So that, when the client programmer calls create()
on the home interface, they'll have a reference to that
bean on which the business methods may be called.
Create()
• All the create() methods must throw …
– java.rml.RemoteException
» because they can be remote methods
– javax.ejb.CreateException
» used to indicate an application-level problem during
attempted creation -- like illegal parameters passed to
create()
• Code coming up
» See page 979
package sportBean.cmp;
import javax.ejb.*;
import java.rmi.RemoteException;
import java.util.Collection;
public interface SportTeamHome extends EJBHome {
SportTeam create(String sport, String nickName)
throws RemoteException, CreateException;
SportTeam create(String sport,String nickName,
String ownerName,
String franchisePlayer)
throws RemoteException, CreateException;
• Each one of these forms of the create()
method, defined in the bean's home
interface . . .
– MUST have two matching methods in the
bean's implementation class
• The two methods for each create() in
the home interface . . .
– MUST be named . . .
• ejbCreate()<<< returns the PK
• ejbPostCreate() <<< returns void
– They MUST . . .
• have the same parameters in the same order as the
create() method
• be declared public
– They must NOT . . .
• be final or static
Point of Confusion
• Why . . .
– ejbCreate() and ejbPostCreate()
» BOTH are REQUIRED!
• Generally
– All the work will be done in ejbCreate(),
leaving ejbPostCreate() empty
• So what gives???
Point of Confusion
• You are not allowed to pass "this" as a
parameter to a remote method;
– You must always the remote interface instead
• BUT
– the REMOTE INTERFACE for the bean is NOT available
UNTIL ejbCreate() returns
– SO,
• if you need you need the remote interface during the
creation of the EJB component . . .
» . . . you be . . . outta luck!
– Enter ejbPostCreate()
» TO SAVE THE DAY!!
Point of Confusion
• The same situation exists with the PK in
CMP
– Because the container creates the key
• If the primary key is needed . . .
– that work needs to be done in
ejbPostCreate()
CMB Stuff
• In a CMB,
– the parameters that are passed in by the client
will be used to initialize the entity bean's state
• Although, the return type of
ejbCreate() is the same as the PK,
– the bean developer should return null
» the container will ignore the returned value anyway
BMP Stuff
• In a BMP, the bean must insert its state into
the underlying data store
– For a relational database
– this means writing an SQL INSERT statement
• The bean developer
– should use the data to initialize the state
variables of the bean
– should construct an instance of the PK and
return it
CMP Stuff
• Code follows
» It's the CMP version of the sports team entity bean's
creation callbacks
» Full code is found on p. 980-1
package sportBean.cmp;
. . .
public class SportTeamEJB implements EntityBean{
. . .
public SportTeamPK ejbCreate(String sport,String nickname)
throws CreateException {
this.sport = sport;
this.nickName = nickName;
ownerName = null;
franchisePlayer = null;
return null;
}
public void ejbPostCreate(String key, String relatedData) {}
public SportTeamPK ejbCreate(String sport,String nickname,
String ownerName,String franchisePlayer) throws
javax.ejb.CreateException {
this.sport = sport;
this.nickName = nickName;
ownerName = null;
franchisePlayer = null;
return null;
}
public void (ejbPostCreate(String sport, String nickName,
String ownerName, String franchisePlayer){}
BMP Stuff
• The same sports team entity bean
– with bean-managed persistence
• Has two basic differences
– the ejbCreate() methods have JDBC and
SQL code to insert a record into the database
– the method returns an instance of a primary
key, rather than null
» See pages 981-3
Read -- ejbLoad()
• The ejbLoad() callback method
– corresponds (roughtly) to the 'read'
functionality of entity beans
• The entity loads the database
– in correspondence to the container's
ejbLoad() call
Read -- ejbLoad()
• With CMP
– the EJB container will take care of transferring
the entity's state from the database to the
entity's instance variables
» That means I can leave ejbLoad() blank!!
» BUT you may want to do some postprocessing, too!
Read -- ejbLoad()
• With BMP
– the bean programmer will write their data
access code . . .
» JDBC and SQL code
– . . . in ejbLoad() to transfer the entity's state
to instance variables
Read -- ejbLoad()
• Technically ejbLoad() doesn't tell the bean
that it must actually load data
• it just tells the bean that it must re-synchornize its
state with the underlying data store
• In fact,
– the bean's persistence implementation may
choose to defer loading the state until that state
is acutally used
ejbLoad() and CMP
• The role of ejbLoad() in CMP is to
process the data after it has been loaded
from the database
– Usually, the data will not need any processing,
and ejbLoad() will be empty
– But it may be the case that some changes are
necessary
» See page 984 for an example
ejbLoad() and BMP
• Here the role of ejbLoad() is to notify the
bean that it must invalidate the current
cached state and prepare for business
method invocations
– Practically, this mean replacing the state by
loading it from the database
• For this you'll need the PK
– by the time that ejbLoad() is called, the PK is associated
with the entity and is available from its context.
– You'll have to add the interfaces and methods on page
984-5
Interface
public EJBObject getEJBObject() throws
IllegalStateException;
pubic Object getPrimaryKey() throws
IllegalStateException;
For BMP
public void setEntityContent(EntityContext ctx) {
this.ctx = ctx;
}
public void unsetEntityContext() {
ctx = null;
}
For CMP
public void setEntityContext(EntityContext ctx)
{}
public void unsetEntityContext() {}
ejbLoad() -- BMP version
• see page 985-6 for the BMP version of
ejbLoad()
• Note is made of how the saved
EntityContext is used to retrieve the
primary key
SportTeamPK primaryKey = (SportTeamPK)
ctx.getPrimary Key();
Update -- ejbStore()
• For a bean with CMP
– ejbStore() is called directly before the container
writes the bean state to the database
– this gives an opportunity to pre-process the
bean's data to ensreu that it is in an appropriate
state for persistent storage
» Typically though this method will be left empty
Update -- ejbStore()
• For a bean with BMP, the programmer is
responsible for providing in this method, the
logic that will transfer the bean's state to the
underlying data store.
» For a relational database this most likely means
JDBC code and SQL statements
Update -- ejbStore()
• NOTE (p. 986)
– "With ejbLoad(), the bean has the option to
defer the actual loading of state until it was
used. There is not such option with ejbStore().
Any modifications to the object's state must be
written to the data store immediately."
ejbStore() for BMP
• Next slide shows the ejbStore for a bean
with BMP
» see page 986-7 of text for complete listing
public void ejbStore() {
Connection con = null;
try {
con = getConnection();
PreparedStatement statement =
con.prepareStatement("UPDATE . . .");
statement.setString(1, ownderName);
statement.setString(2, francisePlayer);
. . .
if (statement.executeUpdate() !=1){
throw new EJBException("Failed to save...");
}
statement.close();
}catch (SQLException sqle) {
throw new EJBException(sqle);
}
finally {
try {
if (con != null) {
con.close();
}
}catch (SQLException sqle) {}
}
}
ejbStore() for CMP
• Next slide shows the ejbStore for a bean
with CMP
» see page 987 of text for complete listing
public void ejbStore() {}
Delete -- Remove()?
• When a client calls remove() on an entity
bean
– data is deleted from the corresponding data
store
• This is in contrast to calling remove on a
stateful session bean
– the EJB container discards the session bean
instance in the application server's temporary
storage -- be sure to call remove() when
done, or else the EJB container will waste
resources
» this is probably a good thing to know!
Delete -- Remove()?
• Note
– "You should not call remove() on an entity bean
unless you want to delete that record. The EJB
container will manage the entity bean's instance
in the container" (p. 987).
Delete -- ejbRemove()
• For a bean with CMP
– Can usually be left blank
» I'm beginning to see a pattern here!
– However, the programmer may want to to do
somethings (such as updating related data, or
notifying other systems) before the entity's
object representation is removed from the
database, and here's the chance to do it.
• Code follows
» p 987
ejbRemove() for CMP
public void ejbRemove() {}
ejbRemove() for BMP
• Code follows, see page 987-8
public void ejbRemove() throws javax.ejb.RemoveException{
Connection con = null;
try {
con = getConnection();
PreparedStatement statement =
con.prepareStatement("DELETE FROM SPORTSTEAMS …");
statement.setString1, sport);
statement.setString2, nickName);
if (statement.executeUpdate() != 1){
throw new EJBException("Failed…");
}
statement.close();
} catch (SQLException sqle){
throw new EJBException(sqle);
}
finally {
try {
if (con !=null) {
con.close();
}
}catch (SQLException sqle) ()
}
}
BMP vs CMP Callbacks
• BMP
– callbacks are responsible for solving the entire
problems of synchronizing the state with the
underlying data store for creates, reads,
updates, and deletes.
• CMP
– with the exception of ejbCreate(), the callbacks
are for fine tuning, and can be left empty
CMP Callbacks
public String ejbCreate(String key, String
relatedData) {
this.key = key;
this.relatedData = relatedData;
}
public void ejbPostCreate(String key, String
related data) {}
public void ejbLoad() {}
public void ejbRemove() {}
public void ejbStore() {}
Deployment Descriptor
• They type of persistence . . .
– bean managed
– container managed
• . . . is specified in the XML deployment
descriptor for the EJB
• The <persistence-type> element of
the DD will be one of
– <persistence-type>Bean</persistence-type>
– <persistence-type>Container</persistencetype>
Deployment Descriptor
• If the bean's persistence is CM, the fields
that are persisted must also be specified in
the deployment descriptor
• Each entry in the DD has the name of the
field in the class (and also a description,
optionally)
• Examples follows
» see page 989
Specifying Persistence Fields
<cmp-field>
<field-name>sport</field-name>
<description>basketball</description>
</cmp-field>
<cmp-field>
<field-name>nickName</field-name>
<cmp-field>
Specifying Persistence Fields
• "All the container-managed fields listed in
the DD must be declared public, and must
not be transient in the bean class. They must
be serializable, primitive types, or
references to other EJBs. In a bean with
container-managed persistence, all the
persistence code must be left to the
container" (p. 989)
Specifying Persistence Fields
• The complete deployment descriptor for the
CMP version of the bean is on page 989-90
• The complete deployment descriptor for the
BMP version of the bean is on page 990.
Caching
• A secondary copy of data typically made for
reasons of performance or convenience.
– The instance variables in your EB that represent
the object's persistent state are actually a cache
of the data in the permanent store.
• The cache suffers from the problem of
– getting out if synch with the permanent store
Caching
• With BOTH BMP and CMP it is the
combined responsibility of . . .
– . . . the EJB container . . .
– . . . and the underlying data store . . .
• . . . to manage the synchronization
• The EJB container calls ejbLoad() and
ejbStore() at those times that it thinks
appropriate to keep the local cache in synch
Caching
• The bean programmer does not need to be
concerned with exactly when the container
will call ejbLoad() and ejbStore()
• Still, it's nice to know some common
stratigies used by EJB containers
First Case
• Two methods called in the same transaction
– After the first method is called the container has
the option of called ejbload() and ejbstore()
– More typically, the container will wait until the
second method is finished
– So basically, the container will call
ejbLoad() and ejbStore() on the
transaction boundaries
Second Case
• Two methods in different transactions
– Again in this case the container calls
ejbLoad() and ejbSave() on the
transaction boundaries
– This must be the case because between
transactions some other process could have
modified the data
• Two exceptions
– If all accesses to the data go through the EJB
container, then ejbLoad() doesn't have to be
called -- cache and store are in synch
– If the application does not require the
absolutely freshest data -- not applicable in a
banking scheme, but perhaps in an e-commerce
application 5-minute old data is okay
Finder Methods
• Every entity bean MUST declare
– findByPrimaryKey()
– For CMP, the implementation will be provided
by the EJB container
• However when the EJB is deployed, additional
information needs to be specified
– in what is currently an application-server-specific format
about how the finder should behave
Finder Methods
• For BMP, the developer must provide the
implementation
• The return type
– One result -- an instance of the PK for that
entity
– Zero or more results -- Collection or
Enumeration
Finder Methods
• Note
– You don't have access to state related instance
variables in the implementation of finder
methods -- NOR any other identity specific
information
» Chart on page 997 may be helpful
• See code on page 994-5 for implementation
of finder methods for BMP
Activation/ Passivation
• For EBs ejbActivate()
– provides notification that the enity bean has
been associated with an identity, and is now
ready for ejbLoad() to be called prior to
busness method invocation
• For EBs ejbPassivate()
– provides notification that the entity bean is
being dissassociated
• For the most part, these methods can be
empty
» see page 996
Lifecycle
• The diagram on page 997 summarizes the
information about container callbacks for
entity beans.
» Enjoy!!
THE END