Overview of Container-Managed Persistence

The EJB specification provides for two different ways of implementing Entity beans. The first approach, covered yesterday, is for the bean provider to embed the persistence logic within the bean itself—hence the name bean-managed persistence or BMP. The second is for the container vendor to provide that logic, either generated by the EJB container vendor's deployment tools or as part of the EJB container itself. Entity beans built this way are called CMP Entity beans.

Note

CMP Entity beans have always been part of the EJB specification, first in EJB 1.0 and then with some minor refinements in EJB 1.1. The changes to CMP Entity beans in EJB 2.0 are substantial—so substantial, in fact, that CMP 1.1 Entity beans are not forward compatible with EJB 2.0.

To deal with this, the EJB specification actually provides two different ways to write CMP Entity beans. The first is the legacy 1.1 approach; beans that are written this way indicate it using an entry in their deployment descriptor. The second is using the new and far more powerful approach introduced in EJB 2.0.

Today, you will be learning only about the new EJB 2.0 approach.


The “anatomy” of CMP Entity beans is very much the same as BMP Entity beans:

  • They have a local-home (or remote home) interface that defines the create methods, the finder methods, optional home methods, and a remove method.

  • They have a local (or remote) interface that defines the business methods of the bean.

  • Obviously, they have the bean class itself that implements methods corresponding to the previously mentioned interfaces, and implements the lifecycle methods inherited from javax.ejb.EntityBean.

  • Finally, they may have a primary key class (and must have one if the primary key is composite).

However, there are some differences. The responsibilities of the bean in the lifecycle methods are different, because there is no longer any requirement to persist the bean's state. This raises the question as to when the state is persisted by the container, because it could be done either before the lifecycle method is called or after. There are changes in the interactions between the container and the bean, as you will see.

Another significant difference is the finder methods. Under BMP, the bean provider writes the appropriate finder methods that interact with the persistent data store. Under CMP, the container will do this work, so there is no longer any need to implement the finder methods in the bean. However, the bean provider must still specify the nature of the query to be performed to obtain the correct data from the data store. This is done using EJB Query Language (EJB QL), appearing in the bean's deployment descriptor. EJB QL shares many similarities with ANSI SQL 92, so you should not have too many difficulties picking it up.

Just as tables in relational databases have relationships, so too do Entity beans. You saw this yesterday with the relationship between the Job bean, which had relationships with the Skill, Location, and Customer beans. Under BMP, the bean provider must write the code that maintains all of these relationships explicitly. If CMP is used, these relationships can be declaratively defined using container-managed relationships, or CMR. Again, the declarations of these associations are in the bean's deployment descriptor.

Relationships between Entity beans are intrinsically fine-grained. For example, a many-to-many relationship between Job and Skill (indicating which skills are needed for such-and-such a job) would involve dealing with many (job,skill) tuples in the case study stored in the JobSkill table. You know that Entity beans can have either a local or a remote interface, and that it's good practice to only ever interact with an Entity bean through its local interface because this reduces network traffic. Because the performance cost of maintaining a fine-grained relationship across the network would be too severe, the EJB specification requires that container-manager relationships between Entity beans are defined only through local interfaces. Indeed, one of the primary reasons for the introduction of local interfaces in the EJB specification was to make CMR feasible.

N-tier Architecture (Revisited Again) and CMP Fields

CMP has an impact on the n-tier architecture that you seen have on several previous days. Figure 7.1 shows an update of a figure that you saw yesterday.

Figure 7.1. CMP Entity beans are split into two components.


There are still four tiers to the architecture—namely, the interface, application, domain, and persistence layers. However, with CMP, the Entity beans split into two components. The first component is provided by you, the bean provider. This defines the bean's local-home and local interfaces, but the implementation of the bean itself is incomplete.

It provides a full implementation of the business methods, but there is no implementation of the accessor methods for the bean's state. Indeed, you will see that the methods are marked as abstract. The concrete implementation of the CMP bean is completed by the EJB container provider. This component has dependencies on both the bean provider's bean, and—of course—on the persistence layer. The first dependency is because the concrete implementation uses the bean provider's abstract bean class as its superclass; in other words, it extends from the CMP bean. The second dependency is because the implementation of the bean performs appropriate data store calls.

You may recognize this design as an instance of the Template design pattern. The abstract CMP bean provided by the bean provider is a template, defining certain mandatory “hook” methods—namely, the accessor methods. The implementation of these hooks is provided by the EJB container in terms of the concrete CMP implementation.

Listing 7.1 shows this for the Job Entity bean. This bean defines a pair of accessor methods (the getter and setter) for each of its fields—ref, customer, description, location, and skills.

Listing 7.1. The JobBean's Fields Are Implied by the Abstract Accessor Methods
 1: package data;
 2:
 3: import javax.ejb.*;
 4: // imports omitted
 5:
 6: public abstract class JobBean implements EntityBean {
 7:
 8:     public abstract void setRef(String ref);
 9:     public abstract String getRef();
10:
11:     public abstract void setCustomer(String customer);
12:     public abstract String getCustomer();
13:
14:     public abstract String getDescription();
15:     public abstract void setDescription(String description);
16:
17:     public abstract LocationLocal getLocation();
18:     public abstract void setLocation(LocationLocal location);
19:
20:     public abstract Collection getSkills();
21:     public abstract void setSkills(Collection skills);
22:
23:     // code omitted
24: }

Each of these accessors is implemented by the concrete CMP implementation. The actual instance variables are effectively part of the subclass' implementation, ultimately populated from the persistent data store.

Caution

This naming scheme throws up a very curious restriction, specifically that cmp-fields must not start with a capital letter. Thus, customer and even cUSTOMER are valid names, but CUSTOMER would not be. This is because the methods capitalize the cmp-fields, and one cannot capitalize a capital!


Another way of thinking about this design is in terms of vertical delegation. The Session beans can call the accessor methods on methods defined in the superclass, but the actual method that is invoked is the implementation defined in the subclass. The superclass CMP bean “delegates” vertically down to its subclass CMP implementation.

This design gives several advantages. One immediate advantage of this pattern is that it gives the EJB container (through the concrete bean implementation) much more control over populating the bean's state, without compromising good OO principles. For example, it is up to the EJB container whether it chooses to obtain all of the bean's state when the bean is activated or created (eager loading), or whether it chooses to fetch the bean's state from the persistent data store as and when needed (lazy loading). Indeed, the concrete implementation may adopt some half-way house, eagerly loading all the scalar data pertaining to the bean but lazily loading data corresponding to bean relationships. Indeed, this advantage is pointed out in the EJB specification (section 10.4.2.1).

Another advantage is that the EJB container only need persist the bean's state to the data store when the bean's state has changed. The concrete implementation can keep track of the before-and-after versions of the bean's state and compare them to see if any have changed as the result of a business method invocation. If a read-only accessor method (a “getter” method) is called, there would be no change in state and so the concrete implementation need not perform an unnecessary update to the data store. Taking this on one further stage, when the bean's state is changed, the EJB container need only update those fields that have changed and can ignore fields that have not changed. This reduces network traffic between the EJB container and the persistent data store.

One final advantage worth mentioning is that some value-add services, such as optimistic locking, can be implemented by EJB container vendors more straight-forwardly.

A Quick Word about the Case Study Database

As you go through the remaining topics for today, you may well want to load up and run the case study code. Before you can do this, the Agency database needs to be modified to support CMP. This is because the J2EE RI container generates its own SQL schema to store the Entity beans' data.

Figure 7.2 shows the revised schema for the case study, as generated by the J2EE RI container.

Figure 7.2. The case study database schema changes under CMP.


The J2EE RI container can automatically create this schema when the Entity beans are deployed. However, because there is example data in the case study database, it is easier to run the provided utility to “upgrade” the database to support CMP. The Agency Session bean queries the Cloudscape RDBMS tables directly. To ensure that this continues to work, the utility also creates SQL views with the names of the old tables (JobSkill and so on) against the new tables.

The steps for converting the database to support CMP are as follows:

1.
Shut down Cloudscape if it is running.

2.
Back up the current (pre day 7) version of the Agency database, under %J2EE_HOME%cloudscape.

Under Windows, you can do this using copy and paste, or from the command line type:

> cd %J2EE_HOME%cloudscape
> xcopy Agency bmpAgency /I /E

Under Unix, you can do this using the following:

$ cd $J2EE_HOME/cloudscape
$ cp –r Agency bmpAgency

3.
Restart Cloudscape.

4.
Under the case study day07Database directory, run the batch CreateCMPAgency.bat (Windows) or CreateCMPAgency.sh (Unix). This calls CreateCMPAgency.java (already compiled for you) which, in turn, creates the previous tables, populates the tables with the same sample data, and creates the views for backward compatibility.

5.
When you have done this, you may want to shut down Cloudscape and then backup the CMP version of the database to a directory called cmpAgency, using similar commands to those in step 2. That way, you can easily switch between the two different schemas. To reinstate either version, just delete the Agency directory and then copy back either the bmpAgency or cmpAgency using xcopy (Windows) or cp -r (Unix).

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

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