The bean developer's view of an entity bean differs from that of the client. Essentially, the bean developer is responsible for the implementation of the methods defined in the bean's component and home interfaces, as well as the callback methods of the EntityBean interface. The developer needs to know how to implement correctly the methods defined by the home interface the find, create, and home methods the business methods, and the methods defined by the EntityBean interface. These method implementations access the state of the entity objects maintained in a resource manager. As a result, the bean developer needs to understand entity object state and persistence to implement the entity bean methods optimally. We begin this section by describing entity object state and persistence. The entity object state is managed by a resource manager. Management of state is separate from the container's management of entity bean instances. The developer can use either the CMP or the BMP approach to access object state. Each of these two persistence approaches has advantages and drawbacks. For entity beans using CMP, the developer can use the EJB QL query language to implement the find methods. EJB QL is an SQL-like query language. The developer can also define additional queries for use internal to the bean itself, using ejbSelect methods. We discuss these concepts in this section. This section also describes various approaches to using the ejbLoad and ejbStore methods. The container invokes these methods on the bean implementation. The developer can use these methods to take advantage of the container's cache management capabilities and to maximize performance. (See Section 7.2.4, Caching Entity Bean State, on page 219.) This section ends with a discussion on how the container manages multiple client invocations on an entity object. 7.2.1 Entity Object State and PersistenceThe methods of an entity bean class access the object's state in a resource manager. Most resource managers, such as relational databases, manage entity objects' state externally to the bean instances (Figure 7.2). Figure 7.2. Entity Object's State Managed by Resource ManagerSeparating the state of the entity objects from the instances of the entity bean class has the following advantages:
The entity bean architecture is flexible about the choice of the type of resource manager in which to store an entity object's state. Examples of resource managers in which the state of an entity bean can be stored are
The state of most entity beans is typically stored in a resource manager external to the EJB container these are the database or application systems noted in the first three examples just presented. The fast secondary memory integrated with the EJB container is a special example. If provided, it typically is used only for storing the state of short-lived entity objects with states that are not accessed by other applications running outside the EJB container. Because a resource manager maintains the state of an entity object, an entity bean instance must use an API to access the state of the associated entity object. (Associating an instance with an entity object is called object activation, and it is explained in Section 7.2.3, Entity Bean Instance Life Cycle, on page 196.) An entity bean instance can access the state of its associated entity object by using two access styles: BMP and CMP. Because CMP is the preferred approach, it is discussed first. Container-Managed PersistenceContainer-managed persistence (CMP) is a resource manager independent data access API tailored for use by entity beans. CMP offers distinct advantages over bean-managed persistence (BMP). Probably the main advantage of CMP involves database access code. It is simpler to write database access code with CMP than to write such code with BMP. Database access with BMP usually entails coding JDBC calls. Using CMP, the developer need only describe what state is to be stored persistently; the container takes care of how the persistence is performed. With BMP, on the other hand, the developer is responsible for both what state to persist and how that state is to be persisted. Another important advantage of CMP is that it greatly enhances an entity bean's portability. A developer uses the same API that is, the EJB CMP methods regardless of the underlying type of resource manager. The same entity bean can thus be used with any type of resource manager. CMP enables the development of entity beans with implementations that can be used with multiple resource manager types and database schemas. The CMP architecture allows ISVs to develop entity beans that can be adapted at deployment to work with customers' preexisting data. Because different customers use different resource manager types and have different database schemas, the deployer needs to adapt an entity bean to each customer's resource manager type and its database schema. Most important, the entity bean developer does not have to write a different implementation of the bean for each customer. Figure 7.3 shows how an entity bean using CMP uses the various resource manager specific APIs to access data in the respective resource managers. Note that the developer has to write only one entity bean class, regardless of the resource manager type. Based on the mapping done by the deployer, the container generates the appropriate data access code for the resource manager API. Therefore, the developer does not need to know or care about the actual resource manager specific code. Figure 7.3. AccountBean Entity Bean Using CMP to Access Resource ManagersThe performance of CMP entity beans is also likely to be significantly better than that of BMP entity beans or session beans using JDBC. This may sound counterintuitive, because developers assume they can code database access calls in a way that is best for their application. However, obtaining good database access performance requires more than correctly coding the access calls. Rather, obtaining good performance requires such techniques as advanced knowledge of database-specific features, connection pooling, an optimized caching strategy for reducing the number of database round-trips, and more. System-level experts who build containers, persistence managers, and application servers know these advanced techniques the best. With CMP, because the container has full control over persistence management, it can optimally manage database access to achieve the highest performance. This fact has been observed with EJB-based benchmarks on several application server products. The EJB 2.0 specification significantly extended the functionality of CMP. The persistent state of an entity bean is described by JavaBeans-like properties, which are represented in the bean class as get and set accessor methods. For example, a persistent field foo would be represented by the getFoo and setFoo methods in the bean class. These get and set methods allow code in the bean class to access the data items comprising the entity object's state. CMP fields are virtual fields and do not appear as instance variables in the entity bean's implementation class. The implementation class instead defines get and set methods, which are declared public and abstract, for each such public variable. The bean provides no implementation for these methods. Instead, the EJB container provides the method implementations. The implementation class, too, is an abstract class for entity beans that use CMP. For example, the same AccountBean class coded using EJB 2.1 CMP would look as shown in Code Example 7.6: Code Example 7.6 AccountBean Entity Bean Using EJB 2.1 CMPpublic abstract class AccountBean implements EntityBean { // Accessor methods for container-managed fields public abstract String getAccountNumber(); // accountNumber public abstract void setAccountNumber(String v); public abstract double getBalance(); // balance public abstract void setBalance(double v); ... // Business methods public void debit(double amount) { setBalance(getBalance() - amount); } } Note also that entity beans using CMP can implement a local or a remote client view. However, an entity bean is not required to have a local client view to use CMP. Because the local interface exposes a bean's methods only to other beans that reside within the same container, there can be fine-grained access between clients and entity beans without an undue performance overhead. Entity beans with local interfaces not only can expose their state to clients but also can use pass-by-reference semantics to pass state between related bean instances. Applications migrating from an EJB 1.0 or 1.1 approach to the EJB 2.0 or 2.1 specification should keep in mind the change to parameter passing. The remote interface approach uses pass-by-value semantics, whereas pass-by-reference mode with local interfaces may result in unintended changes to the state of a passed value or object. With pass-by-value semantics, the invoked method's actions affect only its local copy of a value or object. With pass-by-reference semantics, there is only one copy of a particular value or object. All involved methods reference and act on the state of that one value or object. In the EJB 1.0 and 1.1 specifications, the CMP API depended on mapping the instance variables of an entity bean class to the data items representing an entity object's state in the resource manager. For example, Code Example 7.7 shows the same AccountBean class coded using CMP: Code Example 7.7 AccountBean Entity Bean Using CMPpublic class AccountBean implements EntityBean { // container-managed fields public String accountNumber; public double balance; ... public void debit(double amount) { balance = balance - amount; } } At deployment, the deployer uses tools to generate code that implements the mapping of the instance fields to the data items in the resource manager. Although the EJB 1.1 field-based approach to CMP is still supported for applications implemented prior to the EJB 2.0 specification, this book focuses on the EJB 2.0 CMP approach. Container-Managed RelationshipsAlong with an enhanced CMP approach, the EJB 2.1 specification supports container-managed relationships (CMRs) as part of the CMP architecture. Multiple entity beans are now allowed to have relationships among themselves, referred to as CMRs. Container-managed relationships are described by CMR fields in the deployment descriptor. The EJB container supports one-to-one, one-to-many, and many-to-many relationships, automatically managing the relationships and maintaining their referential integrity. For example, consider a many-to-many bidirectional relationship, such as one between a Supplier entity bean and a Parts entity bean. If a Supplier instance stops providing a particular part, the container automatically removes that Supplier from the set of available suppliers for that Parts instance. CMR fields are handled in the same way as CMP fields. CMR fields do not appear as instance variables in the entity bean's implementation. Instead, the implementation defines public, abstract get and set methods for each CMR public variable. The EJB container provides the method implementations, rather than the bean itself. An entity bean must provide a local client view so that it can be used as the target of a container-managed relationship. For one-to-one and many-to-one relationships, the get and set accessors for a CMR field are defined using the related bean's local interface type. For one-to-many and many-to-many relationships, the get and set accessors use the Java Collection interface, as there are many instances of the related bean. The bean provider specifies the relationships between entity beans in the deployment descriptor. At deployment, these relationship specifications become the schema definition, and the relationships may be captured in a relational database or other resource manager. For example, a relationship between two beans may appear as a foreign key relationship in a relational database. Container-managed relationships are also key to the powerful querying features of the EJB QL query language. They allow a developer to concisely write a query that operates over several related beans. EJB QL Query LanguageThe EJB 2.0 specification introduced EJB Query Language, or EJB QL, a query language that is intended to be portable across EJB containers. EJB QL is an SQL-like language for expressing queries over entity beans with container-managed persistence. EJB QL defines queries for find and select methods for entity beans with container-managed persistence. Prior to the EJB 2.1 specification, the manner and language for forming and expressing queries for find methods were left to each individual application server. Many application server vendors let developers form queries using SQL. However, other vendors used their own proprietary language specific to their particular application server product. In addition, each application server provided its own tool for expressing a query. Because the developer must know the database table and column names to correctly form an SQL query, application server tools that rely on SQL provided a mapping between the database names and SQL statements to help the developer. Under the previous versions of the EJB architecture, each application server handled queries in its own manner. Migrating from one application server to another often required you to use the new server's tool to rewrite or reform your existing queries. For example, you might have to use the new server's tool to rewrite the SQL for the find methods used by the application's entity beans. Application servers developed with early versions of the EJB architecture may also support different physical representations of the query. For example, the server may store the query in the deployment descriptor, or it may store the query someplace else. If kept in the deployment descriptor, the query may be identified with a tag unique to that particular server. These factors combined to reduce the portability of your enterprise bean application among various application servers. EJB QL corrects many of these inconsistencies and shortcomings. EJB QL, designed to be an SQL-like language, defines find and select query methods specifically for entity beans with container-managed persistence. EJB QL's principal advantage over SQL is its portability across EJB containers and its ability to navigate entity bean relationships. EJB QL allows querying or navigation over entity bean relationships. A query can begin with one entity bean and from there navigate to related beans. For example, the query can start with an Order bean and then navigate to the Order's line items. The query can also navigate to the products referenced by the Order's individual line items. However, this navigation requires that the bean relationships be expressed as container-managed relationships in the deployment descriptor. With EJB QL, you can specify the query during in the application development process, and that query is kept in the deployment descriptor. Therefore, you have two options for writing the query: You can use the application server's query-related tools, or you can write the query by manually editing the deployment descriptor. The container generates the query language implementation for queries specified in the deployment descriptor. For example, suppose that CustomerBean had a one-to-many relationship with AccountBean through the container-managed relationship field accounts. You want to form an EJB QL query to traverse from CustomerBean to AccountBean and return all customers with large accounts. You might write the query as follows: SELECT DISTINCT OBJECT(cust) FROM Customer cust, IN(cust.accounts) acct WHERE acct.balance > ?1 ORDER BY cust.firstName In CustomerBean's home interface, a developer might define the find method associated with this query as follows: public Collection findLargeCustomers(int minimumBalance) throws FinderException; As you can see, the EJB QL query looks similar to an SQL query: The query has a SELECT clause, a FROM clause, an optional WHERE clause, and an optional ORDER BY clause. The EJB QL query names beans using their abstract schema names. A bean's abstract schema name, which is declared in its deployment descriptor, uniquely identifies the bean in an EJB QL query. In the preceeding query, the abstract schema name of the CustomerBean is Customer. The SELECT clause specifies the return type of the query. If the return values are to be unique that is, no duplicates add the DISTINCT keyword to the clause. You can indicate the return type by using an identification variable with the syntax OBJECT(cust). This specifies that the query returns objects that are values of the identification variable cust. The return type may also be indicated by a path expression of the form accounts.customer, as long as the path expression ends in a single-valued (one-to-one or many-to-one) CMR or CMP field. You might use a path expression, for example, to implement a find method, findLargeAccounts, that returns a Collection of accounts. A path expression is the construct used to navigate from one bean to a second bean, using a CMR field of the first bean. The return value for find methods can be only the type of the bean on whose home interface the find method is defined. There are no such restrictions on the return value for select methods defined in a bean class; their return values may be Java primitive types or bean types, or they may be collections of these types. Similar to SQL, the return type of an EJB QL query may also be the result of an aggregate function: AVG, MAX, MIN, SUM, or COUNT. For example, SELECT COUNT(cust) returns a count of all Customer objects in the result of the query. The return type of the ejbSelect method whose query uses the COUNT function needs to be the Java primitive type long. The return type of an ejbSelect method using an AVG function needs to be double. The FROM clause declares identification variables used in the SELECT and WHERE clauses. There are two ways to declare identification variables:
The FROM clause in EJB QL is similar in behavior to the FROM clause in SQL. With both FROM clauses, the effect of declaring multiple identification variables is a Cartesian product of the values of each of the identification variables. This means that if any of the clause's identification variables refers to a bean that has zero instances, the return values of the query will be empty. The WHERE clause defines conditions that restrict the set of values returned from the query. The WHERE clause can use operators similar to SQL, including arithmetic (+, -, *, /), comparison (=, >, <, >=, <=, <>), and logical (NOT, AND, OR) operators. Like SQL, EJB QL defines additional constructs for use in the WHERE clause, including
The WHERE clause can also use input parameters, using the syntax ?1, ?2, and so forth. Parameters are numbered starting with 1 and are used in the order in which they appear in the find or select method signature. For example, consider the clause WHERE acct.balance > ?1. At runtime, the query processor substitutes the values of the parameters provided to the find or select method into the query. The ORDER BY clause tells the query processor to order the results in a Collection by a particular CMP field or set of CMP fields. If the return type of the query is a bean type that is, the SELECT clause has OBJECT(cust) such as for find methods, the CMP fields used for ordering must be valid fields of the returned bean type. If the return type of the query is a CMP field type, the ORDER BY clause must use the same CMP field. Ordering can be in ascending or descending order. For example, consider the following clause: ORDER BY cust.firstName ASC, cust.lastName DESC This clause returns a Collection of customers in ascending order by their first names. Those customers within the Collection having the same first name are in descending order by their last names. Ascending order is the default if the ORDER BY clause specifies neither ASC nor DESC. In addition, all null values in the returned Collection either precede or follow all non-null values. We present more EJB QL queries when we look at the entity bean example application in Chapter 8. Although EJB QL offers certain advantages, the language itself is not quite as rich as SQL. In particular, EJB QL cannot form some of the sophisticated queries of which SQL is capable, such as nested queries. However, it is likely that application server query tools will handle these differences between the languages. Future versions of the EJB specification will enhance the richness of EJB QL. Bean-Managed PersistenceWhen it uses BMP, an entity bean uses a resource manager specific interface (API) to access state. (In the BMP approach to managing entity object state persistence, the entity bean itself manages the access to the underlying state in a resource manager.) Figure 7.4 shows three entity bean classes (AccountBean, AccountBean2, and AccountBean3). Each class accesses a different resource manager type. For example, a bean uses JDBC to access state stored in a relational database. In Figure 7.4, AccountBean uses the JDBC API to access state stored in the relational database management system (RDBMS). If the state is stored in a different type of database, the bean uses a different API to access the state, and the API is specific to the resource manager. Thus, AccountBean2 uses an API specific to the RM2 adapter for its RM2-type database. This means that if an entity bean uses BMP, the bean code is, in general, dependent on the type of the resource manager. Figure 7.4. Entity Beans Using BMP to Access Different Resource ManagersFor example, the AccountBean entity bean class may use JDBC to access the state of the Account entity objects in a relational database, as Code Example 7.8 illustrates. In the example, the implementation of the debit method obtains the primary key of the Account entity object currently associated with the instance. The method uses the JDBC API to update the account balance. Note that in a real-life application development, the bean developer would likely use some data access tools, such as command beans, on top of JDBC rather than coding JDBC directly in the entity bean class. Code Example 7.8 Using the JDBC API to Access Statepublic class AccountBean implements EntityBean { ... public void debit(double amount) { Connection con = ...; PreparedStatement pstmt = con.prepareStatement( "UPDATE Account SET acct_balance = acct_balance - ? " + "WHERE acct_number = ?" ); pstmt.setDouble(1, amount); pstmt.setString(2, (String)ctx.getPrimaryKey()); pstmt.execute(); con.close(); } } BMP's main advantage is that it simplifies deploying the entity bean. When an entity bean uses BMP, no deployment tasks are necessary to adapt the bean to the resource manager type or to the database schema used within the resource manager. At the same time, this is also the main disadvantage of BMP, because an entity bean using BMP is, in general, dependent on the resource manager type and the database schema. This dependency makes the entity bean less reusable across different operational environments and also means that the developer has to write much more code to do the resource manager access. However, an entity bean using BMP can achieve some degree of independence of the entity bean code from the resource manager type and the database schema. This can be accomplished, for example, by using portable data access components when developing the BMP entity bean. Essentially, the entity bean class uses the data access components to access the entity object's state. The data access components would provide deployment interfaces for customizing the data access logic to different database schemas or even to a different resource manager type, without requiring changes to the entity bean's code. Figure 7.5 shows the AccountBean entity bean using three APIs to access three resource manager types. This example is very much like Figure 7.4, with one significant difference. Note that instead of three separate entity beans classes (AccountBean, AccountBean2, and AccountBean3) implementing access to the resource manager APIs, a single entity bean class, AccountBean, using data access components, can access the different resource manager specific APIs. The data access components support all three resource manager types. Figure 7.5. Entity Beans Using Data Access Components to Access Resource ManagersOn the surface, this is similar to CMP. There is, however, a significant difference between CMP and the data access component approach. The CMP approach allows the EJB container to provide a sophisticated persistence manager that can cache the entity object's state in the container. The caching strategy implemented by the persistence manager can be tuned without making modifications to the entity bean's code. It is important to note that the CMP cache may be shared by multiple instances of the same entity bean or even by instances of different entity beans. This contrasts with the data access components approach, in which it is not possible, in general, to build a cache that can be shared by multiple instances. 7.2.2 Entity Bean Class MethodsThe bean developer's primary focus is the development of the entity bean class. The bean developer is responsible for writing the implementation of the following methods:
In addition, for entity beans with CMP, the bean developer needs to write abstract get and set accessor methods for container-managed fields and relationships. The developer may also define abstract ejbSelect methods in the CMP bean implementation class for executing EJB QL queries internal to the bean. The following subsections describe these methods in more detail. Section 7.2.3, Entity Bean Instance Life Cycle, on page 196 explains when and in what context the EJB container invokes these methods. The implementation class for entity beans that use EJB 2.0 or 2.1 container-managed persistence must be an abstract class. The implementation class for entity beans that use bean-managed persistence is a concrete class. Entity Bean Accessor MethodsEntity beans using CMP use accessor methods for the container-managed persistent fields. These accessor methods take the place of instance field declarations in the bean class. The get and set accessor methods are declared public and abstract. The bean class does not provide an implementation for these methods, because the EJB container does so. Accessor methods must be declared for both CMP and CMR fields. We've already shown AccountBean's get and set methods for its container-managed fields accountNumber and balance. In addition, AccountBean might maintain a many-to-one relationship between accounts and customers. An account might also be involved in a one-to-many relationship, such as when a single account has a set of detail lines associated to it. If these relationships were implemented as container-managed relationships, AccountBean would include accessor methods for these CMR fields, too (Code Example 7.9): Code Example 7.9 AccountBean Entity Beanpublic abstract class AccountBean implements EntityBean { // Accessor methods for container-managed fields public abstract String getAccountNumber(); // accountNumber public abstract void setAccountNumber(String v); public abstract double getBalance(); // balance public abstract void setBalance(double v); ... // Accessor methods for container-managed relationship fields public abstract Customer getCustomer(); // Customer public abstract void setCustomer(Customer customer); public abstract Collection getAcctDetails(); // Detail lines public abstract void setAcctDetails(Collection acctDetails); } Note that the getCustomer accessor method returns the local entity object type Customer, whereas getAcctDetails returns a Collection of Detail objects. Entity Bean Business MethodsThe bean developer implements in the entity bean class the business methods declared by the entity bean's component interface. The rules for the business method implementations of an entity bean are similar to those for a session bean implementation. The number and types of parameters and the return value type for these business methods must match those defined in the component interface. In addition, the throws clause for the entity bean class business methods must not include more checked exceptions than the throws clause of the corresponding component interface methods. (Note that the methods in the entity bean class can define fewer exceptions than the methods in the remote interface.) Note too that the business methods must be declared public. They must not be declared final or static. Recall that the Account component interface defines the following business methods: double getBalance(); void credit(double amount); void debit(double amount) throws InsufficientFundsException; The bean developer implements these same business methods in the AccountBean class, as follows: public double getBalance() { ... } public void credit(double amount) { ... } public void debit(double amount) throws InsufficientFundsException { ... } Entity Bean Create MethodsThe entity bean class defines ejbCreate and ejbPostCreate methods that correspond to the create methods defined in the home interface. For each create method in the home interface, the bean developer implements an ejbCreate and an ejbPostCreate method in the entity bean class. Remember that an entity bean may choose not to expose the create functionality to clients, in which case the entity bean home interface defines no create methods, and, of course, the bean developer does not implement ejbCreate or ejbPostCreate methods in the bean class. The ejbCreate and ejbPostCreate methods have the same number of parameters, each of which must be of the same type as those defined in the home interface's corresponding create method. However, the ejbCreate methods differ from the create methods, defining the bean's primary key type as their return value type. The ejbPostCreate defines the return type as void. The throws clause for each ejbCreate and ejbPostCreate method must not include more checked exceptions than the throws clause of the corresponding create method. However, the ejbCreate method throws clause can have fewer exceptions than the corresponding create method. Like the business methods, the ejbCreate methods must be declared public. They must not be declared final or static. For example, the Account home interface declares the following create methods: Account create(String lastName, String firstName) throws CreateException, BadNameException; Account create(String lastName) throws CreateException; Account createBusinessAcct(String businessName) throws CreateException; Note that if Account's home interface had implemented a remote view, each of its create methods would have thrown a RemoteException in addition to the other exceptions. The bean developer implements these corresponding ejbCreate and ejbPostCreate methods in the AccountBean class: public AccountKey ejbCreate(String lastName, String firstName) throws BadNameException { .... } public void ejbPostCreate(String lastName, String firstName) throws BadNameException { .... } public AccountKey ejbCreate(String lastName) { .... } public void ejbPostCreate(String lastName) { .... } public AccountKey ejbCreate(String businessName) { .... } public void ejbPostCreate(String businessName) { .... } When creating a new entity instance, the EJB container first invokes the ejbCreate method and then invokes the matching ejbPostCreate method (see the section Invocation of Create Methods on page 199). The ejbPostCreate method can be used for any initialization work that requires the identity of the newly created entity bean in the form of its EJBObject or EJBLocalObject reference. If it needs to pass a reference of the entity object that is being created to another enterprise bean, an instance must do so in the ejbPostCreate method, not in the ejbCreate method. For example, the ejbPostCreate method may pass the created Account object to the Customer object as an argument in the addAccount method: public class AccountBean implements EntityBean { EntityContext ctx; public ejbCreate(Customer cust) { // This would be an ERROR because it is illegal to // invoke ctx.getEJBLocalObject from an ejbCreate method. cust.addAccount((Account)ctx.getEJBLocalObject()); ... } public ejbPostCreate(Customer cust) { // This is correct. cust.addAccount((Account)ctx.getEJBLocalObject()); } ... } Entity Bean Find MethodsFor entity beans with bean-managed persistence, the bean developer must also implement in the entity bean class ejbFind methods that correspond to the find methods defined in the home interface. Recall that an entity bean's home interface defines one or more find methods, which a client uses to locate entity objects. For CMP entity beans, the ejbFind methods are generated by the container using the EJB QL query provided by the bean developer, so the bean developer does not need to write the implementations of ejbFind methods for CMP entity beans. At a minimum, the developer of a BMP entity bean implements an ejbFindByPrimaryKey method corresponding to the findByPrimaryKey method, which is defined by all entity bean home interfaces. This method looks up a single entity object, using the object's primary key. The developer also implements ejbFind methods that correspond to any additional find methods, such as those that return multiple objects, defined by the home interface. Each find method implementation has the same number of parameters, and each parameter is of the same type as the corresponding home interface find method. The entity bean class implementations of the find methods differ in some respects from the home interface definition. In the home interface, the result type of find methods that return single objects, whether the findByPrimaryKey or another find method, is the entity bean's component interface. The result type of the corresponding ejbFind methods is the entity bean's primary key type. Similarly, in the home interface, the result type of find methods returning multiple objects is a collection (java.util.Collection) of objects implementing the component interface. In the implementation class, the result type of the corresponding ejbFind methods that return multiple objects is a collection (java.util.Collection) of objects of the bean's primary key type. Finally, similar to the create methods, the throws clause for each ejbFind method must not include more checked exceptions than the throws clause of the corresponding find method. However, the ejbFind method throws clause can have fewer exceptions than the corresponding find method. The ejbFind methods must be declared public. They must not be declared final or static. For example, the AccountHome interface defines the findByPrimaryKey method and an additional method, findInactive, which returns multiple objects: import java.util.Collection; Account findByPrimaryKey(AccountKey primaryKey) throws FinderException; Collection findInactive(Date sinceWhen) throws FinderException, BadDateException; If the AccountEJB bean is a BMP entity bean, the bean developer implements these methods in the entity bean class as follows: public AccountPrimaryKey ejbFindByPrimaryKey (AccountPrimaryKey primkey) throws FinderException { ... }; public Collection ejbFindInactive(Date sinceWhen) throws BadDateException { ... }; Entity Bean Home MethodsEntity bean classes must also provide an implementation for each home method listed in the home interface. The bean developer implements these home methods with corresponding ejbHome methods. For example, the AccountHome interface includes one home method: public void debitAcctFee (float fee_amt) throws OutOfRangeException; The bean developer implements this method in the entity bean class as follows: public void ejbHomeDebitAcctFee (float fee_amt) throws OutOfRangeException { ... }; Home methods are similar to static methods in Java classes in that they do not operate on a specific entity bean instance that has an identity. Home methods are executed by a bean instance that has not been assigned an identity. As a result, home methods cannot access the identity of the bean by using the getPrimaryKey, getEJBObject, and getEJBLocalObject methods of the EntityContext interface. This also means that home methods cannot call the get or set accessor methods for CMP and CMR fields. However, home methods can call the ejbSelect methods defined in the bean class. This allows home methods to execute queries and to process the results of the queries. Select MethodsSelect methods, available only for CMP entity beans, are similar to find methods in that the bean developer provides the method definitions, but the methods themselves are implemented using EJB QL queries. The bean developer defines select methods as abstract methods in the bean implementation class with a name of the form ejbSelect<METHOD>. The developer also provides an EJB QL query for the ejbSelect method in the bean's deployment descriptor. At deployment, the container's tools generate the implementation code for the ejbSelect method, using the EJB QL query provided by the developer. Keep in mind that ejbSelect methods are not exposed through the home or component interfaces. Hence the client cannot invoke ejbSelect methods directly. The developer may define a home method on the home interface that delegates to the ejbSelect method, and then the client can invoke that home method. However, unlike for a find method, the return value of an ejbSelect method is not restricted to the bean's component interface. In fact, ejbSelect methods can return any type, including the types of the CMP fields in the bean and the local objects of related beans. The return value may also be a single value or a Collection of values. For example, an example of an ejbSelect method definition for the AccountBean follows: public abstract Collection ejbSelectInactiveCustomers (Date sinceWhen); This ejbSelectInactiveCustomers method returns a java.util.Collection object containing the local entity objects for customers whose accounts have been inactive since the date provided in the parameter to the method. EntityBean Interface MethodsAn entity bean class is required to implement the methods defined by the javax.ejb.EntityBean interface. The EJB container invokes these methods on the bean instance at specific points in an entity bean instance's life cycle. Code Example 7.10 shows the definition of the EntityBean interface methods: Code Example 7.10 EntityBean Interfacepublic interface EntityBean extends EnterpriseBean { public void setEntityContext(EntityContext ctx) throws EJBException, RemoteException; public void unsetEntityContext() throws EJBException, RemoteException; public void ejbRemove() throws RemoveException, EJBException, RemoteException; public void ejbActivate() throws EJBException, RemoteException; public void ejbPassivate() throws EJBException, RemoteException; public void ejbLoad() throws EJBException, RemoteException; public void ejbStore() throws EJBException, RemoteException; } Note that although the EntityBean interface methods throw RemoteException, the EJB 2.1 specification mandates that implementations of these methods must not throw RemoteException. 7.2.3 Entity Bean Instance Life CycleEvery entity bean instance has a life cycle that starts from its time of creation and continues through its removal. The EJB container manages the life cycle for every instance of an entity bean class. Bean developers who manually code the entity bean class need to know what happens during an entity bean's life cycle and how that life cycle is managed by the container. On the other hand, bean developers who use an EJB-aware application development tool do not need to know most of this information, because the application development tool may provide a simpler abstraction. This section describes the various stages in the life cycle of entity bean instances, as well as the persistence and transaction management interaction details between the container and entity bean instances. These details are useful for advanced developers trying to tune the performance of their entity beans. Figure 7.6 illustrates the life cycle of an entity bean instance. The diagram shows that an entity bean instance is in one of the following three states:
Figure 7.6. Life Cycle of an Entity Bean InstanceEach entity instance state has defined characteristics. In addition, transitions between states happen as a result of certain actions. The EJB container drives the state transition in response to client-invoked methods from the home and remote interfaces and in response to container-internal events, such as transaction commit, exceptions, or resource management.
Invocation of Create MethodsThis section uses object interaction diagrams (OIDs) to illustrate what happens when an entity object is created with BMP or CMP. Figure 7.7 illustrates creating an entity object with BMP.
Figure 7.7. OID of Creation of Entity Object with BMPWhen the client eventually attempts to commit the transaction, the transaction service orchestrates the commit protocol, as described in the section Transaction-Commit OID on page 210. Note that creation of the entity object is considered part of the transaction. If the transaction fails, the representation of the object's state in the database is automatically deleted, and the entity object does not exist. Figure 7.8 shows the OID for the creation of an entity object with CMP.
Figure 7.8. OID of Creation of Entity Object with CMPInvocation of the remove MethodThe next two figures illustrate removing entity objects. Figure 7.9 shows the steps that take place when removing an entity object with BMP, and Figure 7.10 shows the equivalent steps for removing an entity object with CMP.
Figure 7.9. OID of Removal of an Entity Object with BMPFigure 7.10. OID of Removal of Entity Object with CMPNote that the diagram does not illustrate the transaction-related interactions among the container, transaction service, and database. The removal of the object's state representation from the database step 3 in the diagram is included as part of the transaction in which the remove method is executed. If the transaction fails, the object's state is not removed from the database, and the entity object continues to exist.
Invocation of Find MethodsThis section illustrates find method invocations on entity beans. Figure 7.11 shows the OID for a find method invocation on an entity bean instance with BMP. In contrast, Figure 7.12 shows the execution of a find method on an entity instance with CMP.
Figure 7.11. OID of Find Method Execution on a Bean-Managed Entity InstanceFigure 7.12. OID of Find Method Execution on a Container-Managed Entity InstanceNote that the diagram does not illustrate the transaction-related interactions among the container, transaction service, and database. The database search step 3 in the diagram is included as part of the transaction in which the find method executes. Depending on the isolation level, the found objects may be protected from deletion by other transactions.
Passivation and Activation OIDThe EJB architecture allows the EJB container to passivate an entity instance during a transaction. Figures 7.13 and 7.14 show the sequence of object interactions that occur for entity bean passivation and activation. Figure 7.13 is the OID for passivation and reactivation of an entity instance with BMP.
Figure 7.13. OID of Passivation and Reactivation of a Bean-Managed Entity InstanceFigure 7.14. OID of Passivation and Reactivation of an Entity Instance with CMPFigure 7.14 represents the same operations for an entity instance with CMP.
Transaction-Commit OIDThis section describes the operations that occur during transaction commit. Figure 7.15 shows the object interactions of the transaction-commit protocol for an entity instance with BMP.
Figure 7.15. OID of Transaction Commit Protocol for a Bean-Managed Entity InstanceFigure 7.16 shows the equivalent interactions of the transaction-commit protocol for an entity instance with CMP.
Figure 7.16. OID of Transaction Commit Protocol for CMP Entity InstanceStart of Next Transaction OIDThis section describes the operations that occur at the start of the next transaction. Figure 7.17 shows the object interactions at the start of the next transaction for an entity instance with BMP.
Figure 7.17. OID of Next Transaction for a Bean-Managed Entity InstanceFigure 7.18 shows the object interactions at the start of the next transaction for an entity instance with CMP.
Figure 7.18. OID of Next Transaction for a Container-Managed Entity InstanceCommit OptionsThe entity bean protocol gives the container the flexibility to select the disposition of the instance state at transaction commit. This flexibility allows the container to manage optimally the caching of the entity object's state and the association of an entity object identity with the enterprise bean instances. The container selects from the following commit options:
Table 7.1 summarizes the commit options. As you can see, for all three options, the container synchronizes the instance's state with the persistent storage at transaction commit.
A container can implement some or all of the three commit options. If the container implements more than one option, the deployer can typically specify which option will be used for each entity bean. The optimal option depends on the expected workload.
The selection of the commit option is transparent to the entity bean implementation. The entity bean works correctly regardless of the commit option chosen by the container. The bean developer writes the entity bean in the same way. The object interaction in Transaction-Commit OID on page 210 and Start of Next Transaction OID on page 214 illustrate the commit options in detail. 7.2.4 Caching Entity Bean StateIn this section, we explain how an entity bean can best use the ejbLoad and ejbStore methods in the entity bean class implementation. The container invokes the ejbLoad and ejbStore methods on the instances of both BMP and CMP entity beans. However, using the ejbLoad and ejbStore methods differs between BMP and CMP entity beans. Caching State with BMPRecall from earlier in this chapter that the state of an entity object is kept in a resource manager. Typically, the resource manager resides on a network node different from the EJB container in which the entity bean accessing the state is deployed. Because the implementation of a business method typically accesses the entity object's state, each invocation of a business method normally results in a network trip to the resource manager. If a transaction includes multiple business method invocations, the resulting multiple calls to the resource manager over the network may increase the transaction overhead. Figure 7.19 shows the OID for a transaction with three calls to entity bean business methods. The business methods either read or update the entity object's state stored in the resource manager. Together with the data commit at the end of the transaction, this one transaction includes a total of four network calls to the resource manager.
Figure 7.19. Multiple Invocations to the Resource ManagerMany bean developers will want to reduce the overhead of accessing the resource manager multiple times in a transaction. To accomplish this, the EJB architecture allows the entity bean instance to cache the entity object's state, or part of its state, within a transaction. (Some containers may allow the instance to cache the entity object's state even between transactions. Such a container would use commit option A described in the section Commit Options on page 217.) Rather than making repeated calls to the resource manager to access the object's state, the instance loads the object's state from the resource manager at the beginning of a transaction and caches it in its instance variables. To facilitate caching, the EJB container invokes the ejbLoad method on the instance prior to the first business method invocation in a transaction. The instance can use the ejbLoad method to load the entity object's state, or part of its state, into the instance's variables. Then, subsequently invoked business methods in the instance can read and update the cached state instead of making calls to the resource manager. When the transaction ends, the EJB container invokes the ejbStore method on the instance. If the previously invoked business methods updated the state cached in the instance variables, the instance uses the ejbStore method to synchronize the entity object's state in the resource manager with the cached state. Note that AccountBean in Figure 7.19 did not take advantage of the ejbLoad and ejbStore methods, although the methods were called by the container. Figure 7.20 shows the OID diagram illustrating the use of cached state for the same account balance and debit transactions in Figure 7.19.
Figure 7.20. Caching State in BMP Entity Bean's Instance VariablesThe container invokes the ejbLoad and ejbStore methods as well as the business methods between the ejbLoad and ejbStore methods in the same transaction context. When, from these methods, the entity bean instance accesses the entity object's state in the resource manager, the resource manager properly associates all the multiple resource manager accesses with the transaction; see steps 4 and 13. Note that the container also invokes the ejbStore and ejbLoad methods during instance passivation and activation. The OIDs in the section Passivation and Activation OID on page 206 illustrate this. Because the container needs a transaction context to drive the ejbLoad and ejbStore methods on an entity bean instance, caching of the entity object's state in the instance variable works reliably only if the entity bean methods execute in a transaction context. The ejbLoad and ejbStore methods must be used with great caution for entity beans with methods that do not execute with a defined transaction context. (These would be entity beans with methods that use the transaction attributes NotSupported, Never, and Supports.) If the business methods can execute without a defined transaction context, the instance should cache only the state of immutable entity objects. For these entity beans, an instance can use the ejbLoad method to cache the entity object's state, but the ejbStore method should always be a noop. Caching State with CMPCaching of an entity object's state works differently with CMP. An entity bean with CMP typically does not manage the caching of the entity object's state. Instead, the entity bean relies on the container. The container performs suitable cache management when it maps the CMP and CMR fields to the data items comprising the state representation in the resource manager. Essentially, the EJB container makes it appear that the entity object's state and relationships load into the CMP and CMR fields at the beginning of a transaction and that changes to values of the CMP and CMR fields automatically propagate to the entity object's state in the resource manager at the end of the transaction. The business methods simply access the CMP and CMR fields as if the entity object's state were maintained directly by the class rather than in the resource manager. The container performs the loading and saving of the state transparently to the entity bean's code. The container decides the following, typically using information provided by the deployer:
The container propagates the updates made to the container-managed state to the resource manager immediately after invoking the ejbStore method (Figure 7.21).
Figure 7.21. Caching with CMP Entity BeansAs noted at the start of this section, an entity bean with CMP typically does not use ejbLoad and ejbStore to manage caching of state. (This means that the method implementations in the entity bean class are left empty.) When and how would an entity bean with CMP use the ejbLoad and ejbStore methods? An entity bean with CMP could use the ejbLoad method to compute values derived from the CMP and CMR fields. It would then use the ejbStore method to update the CMP and CMR fields with the updated derived values. The entity bean's business methods could then directly use the derived values. In effect, the bean instance would be caching an alternate representation of the persistent state. Code Example 7.11 illustrates using ejbLoad and ejbStore in CMP entity beans: Code Example 7.11 Using ejbLoad and ejbStore in CMP Entity Beanspublic abstract class AccountBean implements EntityBean { // container-managed fields public abstract String getAccountNumber(); // accountNumber public abstract void setAccountNumber(String v); public abstract double getBalance(); // balance in native // currency public abstract void setBalance(double v); // fields containing values derived from CMP fields double balanceInEuros; ... public double getBalance() { return balanceInEuros; } public void debit(double amountInEuros) { balanceInEuros = balanceInEuros - amountInEuros; } public void credit(double amountInEuros) { balanceInEuros = balanceInEuros + amountInEuros; } public void ejbLoad() { balanceInEuros = balance * conversionFactor; } public ejbStore() { setBalance(balanceInEuros / conversionFactor); } } } AccountBean in Code Example 7.11 is designed for new applications that use the euro as the common currency for all currency calculations. Therefore, the methods of the Account component interface expect currency amounts in euros. However, the legacy account information stored in the resource manager uses the country's native currency. The CMP AccountBean implements the ejbLoad and ejbStore methods to perform the conversions from the native currency to euros, and vice versa. 7.2.5 Designing the Entity Bean Component InterfaceThe entity bean developer is responsible for the design of the bean's component interface. The entity bean developer needs to consider carefully how the bean's clients might use the methods of the component interface. Generally, it's best to implement an entity bean with a local client view. A local client view ensures that the entity bean performs maximally and gives the bean developer the greatest latitude in designing its accessor methods. Because an entity bean with a local client view does not have the remote method invocation performance overhead, the bean developer can include individual accessor methods for each persistent attribute, regardless of the number of attributes. If the application requires a remote view, the bean developer can use a session bean with a remote client view as a facade to entity beans with local views. This approach allows the entity bean to have the advantages of a local client view while at the same time exposing its functionality to remote clients. An entity bean can also be implemented with both a local and a remote client view. Entity Beans with Remote and Local Client ViewsA bean developer can implement an entity bean with both a local and a remote client view. Often, such a dual-purpose entity bean has one or more entity beans with local interfaces behind it. The remote entity bean interface provides a coarse-grained view of the persistent data modeled by the network of entity beans related through their local interfaces. Clients may directly access the entity bean's remote client view. Or, the bean developer may implement a session bean with a remote interface as a facade to the entity bean with both the local and the remote view. A client may access an entity bean method exposed through both the bean's local and remote interfaces. If this occurs, the method is called with pass-by-reference semantics in the local case when the client is located on the same JVM as the entity bean and with pass-by-value semantics in the remote case. To avoid unintended side effects, the bean developer should keep the parameter-passing semantic differences in mind when writing the method. Session Bean As Facade to an Entity BeanA bean developer can implement a session bean with a remote client view and have that session bean serve as a facade to entity beans with local views. Clients use the methods of the remote session bean, which in turn accesses the functionality of the local entity beans. The session bean implements a remote view, making the functionality of the local entity beans available to its remote clients and thus freeing its clients from being restricted to the same Java virtual machine as the session bean. By using session beans in this way, developers can manage the interaction of clients with various entity beans. In addition, the client is exposed to a single interface, which serves as a central entry point to multiple entity beans. The client interacts exclusively with the session bean and may not even be aware of the underlying entity beans in the system. This approach is useful when an application relies on multiple entity beans, as when these beans model complex business data. For particularly complex applications, the bean developer can define different session beans to serve as facades to different functional areas of the application. Generally, however, the developer should not have a session facade for each entity bean, because such an approach is not an efficient use of server resources. Designing Accessor Methods for Entity Beans with Remote ViewsEntity beans should be designed with local views, but some situations require entity beans to use a remote client view. For these situations, we describe three different approaches to the design of the entity bean's remote interface, and discuss the trade-offs with each approach. Accessor Methods for Individual AttributesThe entity bean developer can choose to define the remote interface methods to promote individual access to each persistent attribute. With this style, the entity bean developer defines separate accessor methods in the remote interface for each individual attribute, as shown in Code Example 7.12: Code Example 7.12 Accessor Methods for Individual Attributespublic interface Selection extends EJBObject { Employee getEmployee() throws RemoteException; int getCoverage() throws RemoteException; Plan getMedicalPlan() throws RemoteException; Plan getDentalPlan() throws RemoteException; boolean getSmokerStatus() throws RemoteException; void setEmployee(Employee v) throws RemoteException; void setCoverage(int v) throws RemoteException; void setMedicalPlan(Plan v) throws RemoteException; void setDentalPlan(Plan v) throws RemoteException; void setSmokerStatus(boolean v) throws RemoteException; } This style may be useful when the entity bean may have many attributes and most clients need access to only a few attributes but the set of attributes used by each client is not known beforehand. The client retrieves only the attributes needed. However, there are drawbacks to this style:
Unless the application requires the use of individual access methods, we recommend that the bean developer use one of the two other styles described next for the design of an entity bean's remote interface. Accessing All Attributes in One Value ObjectAs an alternative to accessing attributes individually, the developer can define the remote interface methods to access all attributes in one call. This is a good approach when client applications typically need to access most or all of the attributes of the entity bean. The client makes one method call, which transfers all individual attributes in a single value object. Accessing Separate Value ObjectsIn some cases, the developer may choose to apportion the individual attributes into subsets the subsets can overlap and then define methods that access each subset. This design approach is particularly useful when the entity bean has a large number of individual attributes but the typical client programs need to access only small subsets of these attributes. The entity bean developer defines multiple value objects, one for each subset of attributes. Each value object meets the needs of a client use case; each value object contains the attributes required by a client's use of that entity bean. Defining the appropriate value objects and suitable business methods for the individual use case has two benefits. First, because the business method typically suggests the intended use case, it makes it easier for the client programmer to learn how to use the entity bean. Second, it optimizes the network traffic because the client is sent only the data that it needs, and the data is transferred in a single call. The BankAccount remote interface in Code Example 7.13 illustrates this style: Code Example 7.13 Using Multiple Value Objectspublic interface BankAccount extends EJBObject { // Use case one Address getAddress() throws RemoteException, BankAccountException; void updateAddress(Address changedAddress) throws RemoteException, BankAccountException; // Use case two Summary getSummary() throws RemoteException, BankAccountException; // Use case three Collection getTransactionHistory(Date start, Date end) throws RemoteException, BankAccountException; void modifyTransaction(Transaction tran) throws RemoteException, BankAccountException; // Use case four void credit(double amount) throws RemoteException; void debit(double amount) throws RemoteException, InsufficientFundsException; } The developer of this entity bean recognized three different client use cases for the bean, for which the bean defines the following value objects:
The design of the entity bean reflects this usage, defining the value objects Address, Summary, and Transaction for the three different client use cases. The developer has tailored the BankAccount remote methods for the three client use cases. A fourth client type uses the entity bean to perform debit and credit transactions on the account. The fourth use case does not define any value objects. 7.2.6 Concurrent Invocation of an Entity ObjectRecall that an entity object differs from a session object in terms of its client invocation. Only a single client can use a session object, and the client must ensure that it invokes the methods on the object serially. In contrast, multiple clients can concurrently invoke an entity object. However, each client must invoke the methods of the entity object serially. Although the entity object appears as a shared object that the clients can invoke concurrently, the bean developer does not have to design the entity bean class to be multithreading safe. The EJB container synchronizes multiple threads' access to the entity object. The bean developer depends on the EJB container for appropriate synchronization to an entity object when multiple clients concurrently access the object. This section explains how the EJB container dispatches methods invoked by multiple clients through the entity object's component interface to the entity bean instances so that the potentially concurrent execution of multiple client requests does not lead to the loss of the entity object's state integrity. If you are an advanced EJB developer interested in tuning your application server, you might find this section useful. An EJB container may use one of two typical implementation strategies to synchronize concurrent access from multiple clients to an entity object. It is important to note that, from the bean developer's perspective, it makes no difference which strategy the container uses. The bean developer implements the same code for the entity object, regardless of the container synchronization strategy. One implementation strategy essentially delegates the synchronization of multiple clients to the resource manager. It works as follows:
Note that when it uses this implementation strategy, the container may concurrently dispatch multiple invocations to the same entity object by using a different instance of the entity bean class for each invocation (see Figure 7.22). In Figure 7.22, the two Account 100 instances are associated with the same Account 100 entity object, but each instance is in a different transaction context. Because the transaction context is associated with an instance's access to the resource manager, the resource manager performs the synchronization of the updates from the multiple bean instances to the entity object's state based on the transaction context. An EJB container using this implementation strategy uses commit option B or C described in the section Commit Options on page 217. Figure 7.22. Multiple Clients Using Multiple Instances to Access an Entity ObjectThe second implementation strategy places a greater burden for the synchronization of client calls on the container. With this strategy, the EJB container acquires exclusive access to the entity object's state in the database. The container activates a single instance and serializes the access from multiple transactions to this instance (see Figure 7.23). The container can use any of the commit options A, B, or C if it uses this single-instance strategy. Figure 7.23. Multiple Clients Using Single Instance to Access an Entity Object7.2.7 Using Entity Beans with Preexisting DataIt is important to understand that the representation of an entity object in the resource manager may preexist the deployment of an entity bean. For example, a bank might have been using non-object-based applications that stored account records in a database system. The bank then later developed or purchased an EJB application that included the AccountEJB entity bean, which provided the object-oriented EJB client view of the same account database records (see Figure 7.24). Figure 7.24. Access to Preexisting Data Shared with Legacy ApplicationsThe new EJB application seamlessly coexists with the legacy non-object-based application, as follows:
|