Automatic Bean-Managed Persistence
A Technique for the Persistence of Enterprise JavaBeans Components
The persistence of Enterprise JavaBeans (EJB) components has become an important issue in building scalable enterprise applications based on the J2EE platform. Developers of EJB components are faced with the following challenges:
- Differences in application server and database implementations require runtime switches to make persistence code run in different configurations (the EJB 1.1 specification does not fully specify how container-managed persistence should be implemented, which allows for application server vendor competition but makes persistence implementations differ).
- Changes to the fields in a bean require a re-deployment on the application server after the modification of a deployment descriptor, which can often be a lengthy process during the development cycle.
- The handling of the persistence of dependent classes is not always the same in each application server (some break down the fields in dependent classes while others store dependent classes as a binary string).
- When using bean-managed persistence custom code is required to prevent the component from storing fields that have not changed.
- When using container-managed persistence custom finder methods are not always possible.
Automatic Bean-Managed Persistence (ABMP) (patent-pending) addresses several of the problems faced in EJB component persistence by keeping the persistence code separate from the business logic. This separation provides a framework that allows for different application server and database implementations and removes the need for a deployment descriptor. It provides a portable persistence mechanism that moves with the EJB components and insulates them from the application server and database.
ABMP was created during the development of a real production EJB component suite. Its features include:
- Automatically implemented EJB persistence methods (ejbLoad(), ejbStore(), ejbCreate(), ejbRemove(), etc)
- Support for multiple application servers (J2EE Reference Implementation, WebLogic, JRun, plus extensibility for other application servers)
- Support for multiple databases (Oracle, Cloudscape, SQL Server, plus extensibility for other databases)
- Support for persisting all primitive Java types plus the automatic breakdown of dependent classes into their corresponding fields
- Implementations of common finder methods
- Deployment descriptors do not need to be changed during the development process when fields in dependent classes are added or changed
- Only fields that change are stored to the database on a call to ejbStore()
- Optional on-demand loading of fields for specific cases where large fields must be stored
Automatically implemented EJB persistence methods
ABMP is implemented using a superclass common to all EJB entity beans. This class, AbstractAutoEntityBean, provides the implementations for the EJB persistence methods and finder methods.
Initialization procedure and persistable field graph
When the bean is first initialized (in particular, when setEntityContext() is called for the first time), the AbstractAutoEntityBean class uses introspection to find all of the persistable fields in the bean. Each field is examined (with the exception of transient fields) and mapped over to a corresponding field in the database with the same name. Because the same name is used in both the bean and the database, no deployment descriptor or additional persistence configuration is required. After the field mapping is complete, the corresponding static parts of the SQL statements for ejbLoad(), ejbStore(), ejbCreate() and ejbRemove() are generated.
Default implementations of all bean-managed persistence methods
After the initialization procedure completes, ABMP has a mapping between the bean fields and database fields. With each call to a business method, the pre-generated SQL statements are executed to load and store all of the bean's fields. Introspection is used to set the query parameters and get values from the result set.
Isolation from different database implementations
Although each JDBC compliant database supports the use of SQL, they support it differently. For example, sometimes identifiers need to be quoted and other times they must not be quoted. Occasionally, stored procedures may even need to be used for persisting certain data types. For this reason, an AbstractDatabasePersistence class exists to insulate AbstractAutoEntityBean from database operations. For each database, a different concrete class that extends AbstractDatabasePersistence is created.
Implementations of finder methods
Since the AbstractAutoEntityBean class has a mapping of all of the component fields over to the database fields, it has the opportunity to implement common finder methods. Examples of finders that are implemented are as follows:findByPrimaryKey() - Executes the SQL statements needed to find an instance of the bean by its primary key field.
findByField() - Execute a SQL statement to find a list of bean instances with fields that are equal to a specified value. Since this is a common requirement, many finders will be able to use this method to avoid the need for repetitive SQL statements.
findByFieldAndSort()- Execute a SQL statement to find a list of bean instances with fields that are equal to a specified value, and return those instances sorted by the same or another field.
As with the persistence methods, introspection is used in the execution of the SQL statements to set request parameters and get the responses. With the advent of the EJB 2.0 specification, a query language is provided to help write finders that should insulate developers from the need to write custom SQL code or use an application server specific query tool. In this case the finder methods that AbstractAutoEntityBean provides may be deprecated.
Instead of always creating a binary string out of dependent objects using serialization, ABMP has the ability to map their individual fields over to the database as well. During initialization time AbstractAutoEntityBean finds all of the fields in dependent classes that implement the IPersistable interface, and knows that the fields in these classes should be mapped over to the database. A database specific separator character (such as '$') is used to separate the fields of dependent classes from their superclass. For example, if in the class referenced by the bean field beanField there is a field named referencedField, and the '$' character is used as a separator for a certain database, the resulting database field name will be beanField$referencedField. The nesting of referenced classes may be arbitrarily deep. The separator character is used at each level to indicate another nested field.
There is one additional database field per IPersistable object that stores a boolean value stating whether or not the object is null. By using this value an entire reference to a large IPersistable class may be nulled by changing one database field.
Loading fields on demand
Occasionally there will be the need to persist a large field in an entity bean. One example might be a large byte array. It would become very expensive if every call to a business method required that this field be loaded. Instead, the field may be made transient, then loaded on demand. AbstractAutoEntityBean provides a loadField() method to load a single field in the bean. This method should be called in any business method that needs to use the field.
ABMP helps overcome some significant benefits in developing EJB entity beans, including isolation from application server and database differences and rapid persistence configuration. Because its field mapping is automatic, it is most useful in situations where the user of the bean has no existing database schema. When a more complicated mapping is required between the bean and an existing relational database, an alternative mechanism should be used.
For more information on Compoze Software please visit http://www.compose.com.
Initialization Procedure (1)
ejbStore() for IPersistable class (4)
UML Diagram of ABMP and ADP (5)