- Advantages of CMP Entity Beans over BMP Entity Beans
- CMP 2.0 Entity Bean Sample Application
- Step 1: Implementing the CMP 2.0 Address Entity Bean
- Step 2: Implementing the CMP 2.0 Roster Entity Bean
- Step 3: Implementing the CMP 2.0 Student Entity Bean
- Step 4: Implementing JSP Clients to Test CMP 2.0 Entity Beans
- Step 5: Packaging the CMP 2.0 Entity Beans as an ejb-jar File
- Step 6: Packaging the JSP As a Web Component
- Step 7: Deploying the CMP 2.0 Entity Bean Sample Application
- Step 8: Testing the Sample Application
- A Discussion of the Deployment Descriptor
- Summary
A Discussion of the Deployment Descriptor
Let's choose one EJB, StudentEJB, and look at the pertinent elements from the deployment descriptor file (ejb-jar.xml) that will help to elucidate the key aspects of the abstract persistent schema and the abstract persistent methods of CMP 2.0 entity beans. First, we'll review the structural information of StudentEJB that's familiar to us, namely, the <local-home>, <local>, and <ejb-class> elements specify the LocalStudentHome and LocalStudent interfaces and the StudentEJB bean class. The <persistent-type> element specifies that the persistence is managed by the container, and the <cmp-version> element specifies that StudentEJB implements EJB 2.0 persistence. The primary key class is of type java.lang.String, as indicated by the <prim-key-class> element, and StudentEJB does not support callbacks, as specified by the <reentrant> element.
_____.. <enterprise-beans> <entity> <display-name>StudentEJB</display-name> <ejb-name>StudentEJB</ejb-name> <local-home> j2eebootcamp.developingEJB.chapter11.cmp.LocalStudentHome </local-home> <local>j2eebootcamp.developingEJB.chapter11.cmp.LocalStudent</local> <ejb-class> j2eebootcamp.developingEJB.chapter11.cmp.StudentEJB</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.String</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version>
Now, let's look at the abstract persistent schema. In the StudentEJB class, we declared several CMP abstract methods, such as set/getStudentID(), set/getFirstName(), and set/getLastName(). During the deployment of StudentEJB, we specified Student as the name of the abstract persistent schema and the EJB QL for finder methods. All of that information is saved in the deployment descriptor file, as shown in the code fragment that follows. Notice that the <abstract-schema-name> element specifies Student as the name of the schema, followed by the <cmp-field> element that encloses the optional <description> and mandatory <field-name> elements. The StudentID from the getStudentID() abstract method maps to the <field-name>studentID</field-name>, but notice that the first letter of StudentID must be lowercase. This rule applies to both the CMP and the CMR fields. The <primaryKey-field> element is used to specify the primary key for the entity bean.
<abstract-schema-name>Student</abstract-schema-name> <cmp-field> <description>no description</description> <field-name>studentID</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>lastName</field-name> </cmp-field> <cmp-field> <description>no description</description> <field-name>firstName</field-name> </cmp-field> <primkey-field>studentID</primkey-field> <security-identity> <description></description> <use-caller-identity></use-caller-identity> </security-identity>
Notice that we declared three finder methods in the LocalStudentHome interface but didn't have to implement them in the StudentEJB bean class. In CMP 2.0, the container is responsible for implementing the finder methods, so the finder method is mapped in the deployment descriptor with the <query> element. The <query> element encloses several elementsthe <query-method> element that includes the method name as enclosed by <method-name>, and the argument-type, enclosed by the <method-param> element. If there were more than one argument, there would be a matching number of <method-param> elements. The finder method, findByFirstName, is mapped to the EJB QL query statement by the <ejb-ql> element that encloses the EJB QL statement specified during the deployment. With the exception of the findByPrimaryKey() method, for every other finder method declared in the home interface, the container will define <query> elements in the deployment descriptor.
<query> <description></description> <query-method> <method-name>findByFirstName</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql>SELECT DISTINCT OBJECT(s) FROM Student AS s WHERE s.firstName = ?1</ejb-ql> </query> <query> <description></description> <query-method> <method-name>findByLastName</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql>SELECT DISTINCT OBJECT(s) FROM Student AS s WHERE s.lastName = ?1</ejb-ql> </query> </entity>
The relationship information is enclosed within the <relationship> element. During the deployment phase, we specified that the StudentEJB and AddressEJB bean instancess had a one-to-many relationship; this is specified in the deployment descriptor by the <multiplicity> element of One for StudentEJB and of Many for AddressEJB. The StudentEJB bean class declared two CMR abstract methods, and the getAddresses () abstract method returned java.util.Collection. During deployment, we specified that StudentEJB has a one-to-many relationship with AddressEJB and that StudentEJB references AddressEJB with CMR fields addresses, which is a type of collection as shown in Figure 11-14. The <cmr-field> element uses two subelements to specify the CMR field; the <cmr-field-name> element specifies the CMR field and addresses; and the <cmr-field-type> element specifies the Collection type, as shown in the following code fragment. The <cascade-delete> element reflects your selection of the Delete When Bean A is Deleted option during deployment. Also notice that because AddressEJB declares no CMR abstract methods, there are no <cmr-field> elements declared in the AddressEJB section of the deployment descriptor.
<relationships> _____.. <ejb-relation> <ejb-relation-name>Student-has-many-Addresses</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>StudentEJB</ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>StudentEJB</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>addresses</cmr-field-name> <cmr-field-type>java.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>AddressEJB</ejb-relationship-role-name> <multiplicity>Many</multiplicity> <cascade-delete /> <relationship-role-source> <ejb-name>AddressEJB</ejb-name> </relationship-role-source> </ejb-relationship-role> </ejb-relation> _____.. </relationships>
Why return null in ejbCreate() method?
In EJB 1.0, the EJBCreate() method in CMP entity beans declared the returned type void but in EJB 1.1 this method was changed to return primary key types with an actual return value of null. This change was made to facilitate using BMP entity beans to extend CMP entity beans. In essence, EJB 1.1 enabled vendors to support container-managed persistence by extending CMP entity beans with BMP entity beans. This solution worked in EJB 1.1, but was not applicable to the complexity of CMP 2.0 entity beans. Nevertheless, it provides backward compatibility and enables subclassing of bean managed persistence. In general, avoid it in EJB 2.0 unless backward compatibility is one of your concerns.