[ Team LiB ] |
Creating CMP Entity BeansIn this section, we create a CMP version of the Doctor Entity bean from the last section. This approach illustrates the differences between BMP and CMP from a coding standpoint. Creating the Home InterfaceThe Home interface does not change from BMP to CMP. The clients of the Entity bean use the same creation and finder methods from the Home interface. Creating the Value ObjectThe same DoctorVO class from the BMP example is used with this CMP example. The value object for BMP does not need to be any different that the one used for CMP. Creating the Remote InterfaceJust like the Home interface, EJB clients use the same remote methods, individual getters/setters, and bulk getters/setters. Creating the Bean ClassThis is where the most of the differences between BMP and CMP lie. BMP Entity bean methods provide the persistence mechanism, whereas CMP Entity beans contain only the business logic—the container takes care of effectively managing the data store. (Many of the CMP bean implementation's methods are simply notifications.) This is accomplished by creating an abstract bean class with abstract getter and setter methods for the EJB fields. When the EJB compiler (EJBC) compiles this EJB, a concrete base class with concrete getter and setter methods is generated. This class and its methods contain additional logic to support optimized data store access. Listing 22.8 shows the complete CMP bean class. Listing 22.8 The Full Code of the Entity Bean Classpackage wls8unleashed.ejb.entity.cmp; import javax.ejb.*; abstract public class DoctorEJB implements EntityBean { private EntityContext ctx; abstract public Integer getId(); abstract public void setId(Integer id); abstract public String getFirstName(); abstract public void setFirstName(String firstName); abstract public String getLastName(); abstract public void setLastName(String lastName); abstract public String getSpecialty(); abstract public void setSpecialty(String dob); public void setEntityContext(EntityContext ctx) { this.ctx = ctx; } public void unsetEntityContext() { this.ctx = null; } public void ejbActivate() {} public void ejbPassivate() {} public void ejbLoad() {} public void ejbStore() {} public void ejbRemove() {} public Integer ejbCreate(DoctorVO vo) throws CreateException { setId(vo.getId()); setFirstName(vo.getFirstName()); setLastName(vo.getLastName()); setSpecialty(vo.getSpecialty()); return null; } public void ejbPostCreate(DoctorVO vo) { } public DoctorVO getDoctorData() { DoctorVO vo = new DoctorVO(); vo.setId(getId()); vo.setFirstName(getFirstName()); vo.setLastName(getLastName()); vo.setSpecialty(getSpecialty()); return vo; } public void setDoctorData(DoctorVO vo) { setFirstName(vo.getFirstName()); setLastName(vo.getLastName()); setSpecialty(vo.getSpecialty()); } } The ejbCreate() is the only ejb...() method that is not simply a notification. It fills the key field and NOT NULL fields with dummy values so that the bean can be created. It does not insert anything into the database. Even though the return type of ejbCreate() is always NULL, the ejbCreate() method returns the primary key. The container knows how to create the primary key from the bean's key fields. Creating the Deployment DescriptorsDeployment descriptors are another area in which BMP and CMP Entity beans differ greatly. Although there is much less code and logic in the CMP Entity bean class, much more is present in its deployment descriptors. The Deployment DescriptorsThe ejb-jar.xml file needs to change to support CMP persistence. The new version is shown in the following listing. The major change is that we mention the container-managed fields as well as the EJB-QL query codes for the finder methods. Listing 22.9 shows the full code of ejb-jar.xml. You can ignore the <query> blocks in the code for now. They're related to the EJB query language and are covered later in this chapter. Listing 22.9 ejb-jar.xml<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc. //DTD Enterprise JavaBeans 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'> <ejb-jar> <enterprise-beans> <entity> <ejb-name>DoctorEJB</ejb-name> <home>wls8unleashed.ejb.entity.cmp.DoctorHome</home> <remote>wls8unleashed.ejb.entity.cmp.Doctor</remote> <ejb-class>wls8unleashed.ejb.entity.cmp.DoctorEJB</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.Integer</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>Doctor</abstract-schema-name> <cmp-field> <field-name>id</field-name> </cmp-field> <cmp-field> <field-name>firstName</field-name> </cmp-field> <cmp-field> <field-name>lastName</field-name> </cmp-field> <primkey-field>id</primkey-field> <query> <query-method> <method-name>findBySpeciality</method-name> <method-params> <method-param>String</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM Doctor AS a WHERE a.speciality > ?1]]> </ejb-ql> </query> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>containerManaged</ejb-name> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> <ejb-client-jar>ejb20_Doctor.jar</ejb-client-jar> </ejb-jar> The following describes the different parts of this XML file:
We mentioned earlier that we need an additional deployment descriptor for CMP. This is a WebLogic-specific deployment descriptor that maps the container-managed fields to the specific columns in the database. Listing 22.10 shows this deployment descriptor. Listing 22.10 weblogic-cmp-rdbms.xml<?xml version="1.0"?> <!DOCTYPE weblogic-rdbms-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB RDBMS Persistence//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-rdbms20-persistence-810.dtd'> <weblogic-rdbms-jar> <weblogic-rdbms-bean> <ejb-name>containerManaged</ejb-name> <data-source-name>Doctor</data-source-name> <table-map> <table-name>Doctor</table-name> <field-map> <cmp-field>id</cmp-field> <dbms-column>id</dbms-column> </field-map> <field-map> <cmp-field>firstName</cmp-field> <dbms-column>firstName</dbms-column> </field-map> <field-map> <cmp-field>lastName</cmp-field> <dbms-column>firstName</dbms-column> </field-map> <field-map> <cmp-field>speciality</cmp-field> <dbms-column>speciality</dbms-column> </field-map> </table-map> </weblogic-rdbms-bean> <create-default-dbms-tables>False</create-default-dbms-tables> </weblogic-rdbms-jar> Let's explore the XML file in more detail.
We've briefly demonstrated the basics of writing an Entity bean following the EJB specification's BMP and CMP flavors. A new feature with EJBs and in WebLogic is the management of relations within EJBs. Previously, one-many relations and many-many relations had to be modeled either through BMP or through some other mechanism. With EJB 2.x, those relations can now be managed through CMP. We discuss this in the next section. Container-Managed RelationsIn this section, we discuss one-to-one, one-to-many, and many-to-many relationship mappings and show you how to support them through the deployment descriptors. One-to-One RelationshipsA one-to-one relationship is one in which for each and every Entity A, there is one and only one Entity B. In our Doctor example, we could assume that each Doctor has one and only one assistant. The following excerpts show how this would be mapped in the ejb-jar.xml and the weblogic-cmp-rdbms.xml files. Listing 22.11 presents an excerpt from the ejb-jar.xml file showing a one-to-one relationship. Listing 22.11 ejb-jar.xml Excerpt<relationships> <ejb-relation> <ejb-relation-name>Doctor-assistant<ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Doctor-has-an-Assistant </ejb-relationship-role-name> <multiplicity>One<multiplicity> <relationship-role-source> <ejb-name>DoctorBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>DoctorAssistant</cmr-field-name> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Assistant-belongs-to-Doctor </ejb-relationship-role-name> <mulitiplicity>One</multiplicity> <relationship-role-source> <ejb-name>AssistantBean</ejb-name> </relationship-role-source> </ejb-relationship-role> <ejb-relation> </relationships> The <relationships> tag block is placed after the definitions of the enterprise beans in the </enterprise-beans> tag. For each <ejb-relation>, there are two <ejb-relationship-role> tags—one for each side of the relationship. Each one declares the multiplicity of the relationship, the source EJB, and the CMP field of the source EJB that the relationship operates on. The <multiplicity> tag can have the value of One or Many. To represent a 1:1 relationship, both <multiplicity> tags in each <ejb-relationship-role> have to be set to One. For 1:n relationships, the entity on the many side of the relationship (Emp, in our case) has its <multiplicity> tag set to Many. For a n:m relationship, both <multiplicity> tags are set to Many. Listing 22.12 shows an excerpt from the weblogic-cmp-rdbms.xml.xml showing a one-to-one relationship. Listing 22.12 weblogic-cmp-rdbms.xml.xml Excerpt<weblogic-rdbms-relation> <relation-name>Doctor-Assistant</relation-name> <weblogic-relationship-role> <relationship-role-name>Doctor-Has-Assistant</relationship-role-name> <relationship-role-map> <column-map> <foreign-key-column>assistantName</foreign-key-column> <key-column> assistantName </key-column> </column-map> </relationship-role-map> </weblogic-relationship-role> </weblogic-rdbms-relation> It's important to watch out for a few things when working with CMP relationships. Relationships cannot be initialized in ejbCreate(). ejbPostCreate() is used to save the relation fields. The exception to this rule is when a primary key contains a foreign key. Also, collection relation field getters return non-mutable objects. Trying to change the collection gives exceptions. This is as stipulated in the specification and it wouldn't be fast, anyway. Solution: Don't use collection getters except for read-only. Write new methods to add, remove, modify, and empty the collection. One-to-Many RelationshipsOne-to-many relationship means that for an Entity A, there can be one or more Entities of B. In our case, we can model a scenario in which a doctor sees multiple patients. This is a one-to-many relationship between a doctor and patients. The following excerpt shows how this would be mapped in the ejb-jar.xml file and the weblogic-cmp-rdbms.xml file. Listing 22.13 presents an excerpt from the ejb-jar.xml file showing a one-to-many relationship. Listing 22.13 ejb-jar.xml Excerpt<relationships> <ejb-relation> <ejb-relation-name>Doctor-Patient<ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Doctor-has-an-Patient </ejb-relationship-role-name> <multiplicity>One<multiplicity> <relationship-role-source> <ejb-name>DoctorBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>doctorPatient</cmr-field-name> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Patient-belongs-to-Doctor </ejb-relationship-role-name> <mulitiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>PatientBean</ejb-name> </relationship-role-source> </ejb-relationship-role> <ejb-relation> </relationships> Listing 22.14 is an excerpt from the weblogic-cmp-rdbms.xml file showing a one-to-many relationship. Listing 22.14 weblogic-cmp-rdbms Excerpt<weblogic-rdbms-relation> <relation-name>Doctor-Patient</relation-name> <table-name>doctorPatient</table-name> <weblogic-relationship-role> <relationship-role-name>Doctor-Have-Patients</relationship-role-name> <relationship-role-map> <column-map> <foreign-key-column>assistantName</foreign-key-column> <key-column> assistantName </key-column> </column-map> </relationship-role-map> </weblogic-relationship-role> <weblogic-relationship-role> <relationship-role-name>Assistant-Belongs-To-Doctor</relationship-role-name> <relationship-role-map> <column-map> <foreign-key-column>doctorName</foreign-key-column> <key-column> doctorName </key-column> </column-map> </relationship-role-map> </weblogic-relationship-role> </weblogic-rdbms-relation> Many-to-Many RelationshipsA many-to-many relationship is one where both entities are interrelated. In our example, it's quite typical for a doctor to works at more than one hospital and each hospital has many doctors. This is a typical many-to-many relationship. The following excerpts show how this would be mapped in the ejb-jar.xml and weblogic-cmp-rdbms.xml files. Listing 22.15 shows an excerpt from the ejb-jar.xml showing a many-to-many relationship. Listing 22.15 ejb-jar.xml Excerpt<relationships> <ejb-relation> <ejb-relation-name>Doctor-Hospital<ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Doctor-have-Hospital </ejb-relationship-role-name> <multiplicity>Many<multiplicity> <relationship-role-source> <ejb-name>HospitalBean</ejb-name> </relationship-role-source> <cmr-field> <cmr-field-name>doctorHospital</cmr-field-name> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Hospital-have-Doctor </ejb-relationship-role-name> <mulitiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>DoctorBean</ejb-name> </relationship-role-source> </ejb-relationship-role> <ejb-relation> </relationships> Listing 22.16 shows an excerpt from the weblogic-cmp-rdbms.xml showing a many-to-many relationship. Listing 22.16 weblogic-cmp-rdbms Excerpt<weblogic-rdbms-relation> <relation-name>Doctor-Hospital</relation-name> <table-name>doctorHospital</table-name> <weblogic-relationship-role> <relationship-role-name>Doctor-Have-Hospitals</relationship-role-name> <relationship-role-map> <column-map> <foreign-key-column>hospitalName</foreign-key-column> <key-column> hospitalName </key-column> </column-map> </relationship-role-map> </weblogic-relationship-role> <weblogic-relationship-role> <relationship-role-name>Hospitals-Have-Doctors</relationship-role-name> <relationship-role-map> <column-map> <foreign-key-column>doctorName</foreign-key-column> <key-column> doctorName </key-column> </column-map> </relationship-role-map> </weblogic-relationship-role> </weblogic-rdbms-relation> There is another concept with respect to relationships in Entity beans: directionality. Relationships can be unidirectional or bidirectional. Unidirectional RelationshipsA unidirectional relationship between Entity A and Entity B is one in which Entity A knows about Entity B, but Entity B has no knowledge of Entity A. That is, Entity A has relation field getters and setters to access Entity B, but Entity B has no relation fields pointing back to Entity A. This type of relationship is implemented by specifying a cmr-field deployment descriptor element for the Entity bean from which the relationship originates, and not specifying a cmr-field element for the other Entity bean. Bidirectional RelationshipsA bidirectional relationship is one in which Entity A and Entity B are aware of each other. This type of relationship is implemented by specifying a cmr-field deployment descriptor element for each of the Entity beans. All examples you saw prior to the last section were bidirectional. Now that we know how to implement relationships for EJBs in WebLogic, let's now talk about caching. Let's discuss various EJB caching techniques to improve the performance of EJBs in WebLogic. |
[ Team LiB ] |