Deploying an Entity Bean Using CMP

   

After you've implemented a bean class, the next step is to define its deployment descriptor. This section covers what you have to specify to deploy a CMP entity bean. The examples given here are representative of a typical deployment. Refer to Chapter 15, "Deployment," for a more complete discussion of the deployment descriptor contents.

The Abstract Persistence Schema

The deployment descriptor for a CMP entity bean contains a description of its persistent fields and relationships known as its abstract persistence schema . The information provided in the ejb-jar.xml deployment descriptor defines a logical view of an entity and its associations but it doesn't define a physical mapping to the underlying data store. It's up to the deployer to provide that mapping using tools specific to the CMP implementation. As far as what the container needs, the schema identifies the methods that are intended to provide access to the persistent fields and relationships managed by the container. This is accomplished using a set of cmp-field and cmr-field entries in the deployment descriptor.

Every virtual field that appears in your entity bean class (based on your abstract method declarations) must be identified in the abstract persistence schema as a cmp-field . You do this using entries like those shown in the following example:

 <entity>    <ejb-name>EnglishAuction</ejb-name>    <local-home>com.que.ejb20.auction.model.EnglishAuctionHome</local-home>    <local>com.que.ejb20.auction.model.EnglishAuction</local>    <ejb-class>com.que.ejb20.auction.model.EnglishAuctionCMPBean</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>EnglishAuction</abstract-schema-name>    <cmp-field>      <description>The primary key field</description>      <field-name>idField</field-name>    </cmp-field>    <cmp-field>      <field-name>nameField</field-name>    </cmp-field>    <cmp-field>      <field-name>descriptionField</field-name>    </cmp-field>    ...    <primkey-field>idField</primkey-field>    ...  </entity> 

The abstract-schema-name can be any valid Java identifier you want to assign, but it must be unique among those declared within a deployment descriptor. As shown in this example, the name of each CMP field always must begin with a lowercase letter. Standard JavaBean naming conventions are followed when matching deployment descriptor entries to your abstract methods. For example, a CMP field named descriptionField must have corresponding setDescriptionField and getDescriptionField methods declared in the bean class. Notice in this deployment descriptor example that there is nothing specified about how these fields are mapped to the database. The ejb-jar deployment descriptor is only used to identify the persistent fields. The deployer tools and container-specific deployment descriptors define the mapping of each abstract persistence schema to the corresponding data store.

Note

Besides being unique within a deployment descriptor, the ejb-name and abstract- schema-name entries you define must not be the same as any of the EJB Query Language (EJB QL) identifiers. You're pretty safe on this because these reserved identifiers are strings such as WHERE and EMPTY . EJB QL and its uses are described in Chapter 8, "EJB Query Language."


The primkey-field element in the deployment descriptor was first introduced in Chapter 5. This entry only applies to CMP, and you need to use it only when you have a single-field primary key. If so, you must include this entry and define its value to be the name of the CMP field that represents the primary key for the bean.

Relationships between entity beans are defined using ejb-relation entries within the relationships section of ejb-jar . Listing 7.2 illustrates how this is done.

Listing 7.2 The relationships Element Defines Container-Managed Relationships
 <ejb-jar>    <enterprise-beans>      <entity>        <ejb-name>EnglishAuction</ejb-name>        ...      </entity>      <entity>        <ejb-name>AuctionBid</ejb-name>        ...      </entity>      <entity>        <ejb-name>Item</ejb-name>        ...      </entity>        ...    </enterprise-beans>    ...    <relationships>      <ejb-relation>        <ejb-relation-name>EnglishAuction-AuctionBid</ejb-relation-name>        <ejb-relationship-role>          <ejb-relationship-role-name>auction-has-bids          </ejb-relationship-role-name>          <multiplicity>one</multiplicity>          <relationship-role-source>            <ejb-name>EnglishAuction</ejb-name>          </relationship-role-source>          <cmr-field>            <cmr-field-name>bids</cmr-field-name>            <cmr-field-type>java.util.Collection</cmr-field-type>          </cmr-field>        </ejb-relationship-role>        <ejb-relationship-role>          <ejb-relationship-role-name>bid-belongs-to-auction          </ejb-relationship-role-name>          <multiplicity>many</multiplicity>          <cascade-delete/>          <relationship-role-source>            <ejb-name>AuctionBid</ejb-name>          </relationship-role-source>          <cmr-field>            <cmr-field-name>auction</cmr-field-name>          </cmr-field>        </ejb-relationship-role>      </ejb-relation>      ...      <ejb-relation>        <ejb-relation-name>EnglishAuction-Item</ejb-relation-name>        <ejb-relationship-role>          <ejb-relationship-role-name>auction-offers-item          </ejb-relationship-role-name>          <multiplicity>one</multiplicity>          <relationship-role-source>            <ejb-name>EnglishAuction</ejb-name>          </relationship-role-source>          <cmr-field>            <cmr-field-name>item</cmr-field-name>          </cmr-field>        </ejb-relationship-role>        <ejb-relationship-role>          <ejb-relationship-role-name>item-is-offered-by-auction          </ejb-relationship-role-name>          <multiplicity>one</multiplicity>          <relationship-role-source>            <ejb-name>Item</ejb-name>          </relationship-role-source>        </ejb-relationship-role>      </ejb-relation>      ...    </relationships>    ...    <assembly-descriptor>    ...    </assembly-descriptor>    ...  </ejb-jar> 

The example in Listing 7.2 illustrates a one-to-many relationship between an auction and all its bids and a one-to-one relationship between an auction and the item it offers. For each ejb-relation , you can define any unique ejb-relation-name you wish. You're then required to define an ejb-relationship-role for each side of the relationship. Here, you also can use any identifier you wish for the ejb-relationship-role-name as long as it's unique within the file. The multiplicity element defines the number of objects of the source entity that appear in the relationship. In this example, the one-to-many relationship between an auction and its bids is indicated by specifying one as the value for the EnglishAuction multiplicity and many for AuctionBid . Notice that a cascade-delete entry appears in the relationship between an auction and its bids. This instructs the container to delete associated AuctionBid objects whenever an auction is removed. You don't have to include a value for this entry in the deployment descriptor; you just include the tag if it applies. An item isn't owned by an auction, so cascade-delete isn't specified for that relationship.

The relationship-role-source identifies an entity involved in a relationship using its ejb- name . The presence of a cmr-field after the relationship-role-source element determines the navigability of a relationship. In the mapping between EnglishAuction and Item , a cmr- field is defined to allow the auction to navigate to the item. Because an item cannot navigate to an associated auction, no cmr-field is defined for the item's side of the relationship. This allows an auction to offer an item without the item implementation knowing anything about auctions. In contrast, the cmr-field entries for an auction and its bids result in a bidirectional relationship between these entities. Just like a CMP field, a cmr-field-name that appears in the deployment descriptor must be a valid Java identifier that begins with a lowercase letter and corresponds to a pair of abstract get and set methods in the bean class. For one-to-many and many-to-many relationships, you also need to indicate whether the CMR field is declared to use a Collection or a Set using a cmr-field-type entry.

For more information on deploying associated entity beans, see "The relationships Element," p. 432 .

Implementing Finder and Select Methods

The finder methods declared by a bean's home interface are defined by entries in the deployment descriptor. You don't provide any implementation for finder methods in a CMP bean class (not even an abstract method declaration). Finder methods are specified using a SQL-like syntax defined in Chapter 8 as EJB QL. Two examples of finder method query definitions are shown in Listing 7.3.

Listing 7.3 The query Element Defines a Query for a Finder or Select Method
 <ejb-jar>    <enterprise-beans>      <entity>        <ejb-name>EnglishAuction</ejb-name>        ...        <query>          <query-method>            <method-name>findAllAuctions</method-name>            <method-params/>          </query-method>          <ejb-ql>            <![CDATA[ SELECT OBJECT(a) FROM EnglishAuction AS a]]>          </ejb-ql>        </query>        <query>          <query-method>            <method-name>findNonPendingAuctions</method-name>            <method-params/>          </query-method>          <ejb-ql>            <![CDATA[ SELECT OBJECT(a) FROM EnglishAuction AS a              WHERE a.statusField <> 'Pending']]>          </ejb-ql>        </query>        <query>          <query-method>            <method-name>ejbSelectAuctionedItems</method-name>            <method-params/>          </query-method>          <ejb-ql>            <![CDATA[ SELECT OBJECT(i) FROM EnglishAuction AS a, IN(a.item) i]]>          </ejb-ql>        </query>        ...      </entity>      ...    </enterprise-beans>    ...  </ejb-jar> 

As shown here, a query-method element is used to identify a finder method declared in the bean's home interface. If you have a finder method declared in both the remote home and local home with the same name and parameter list, the container can implement both methods from a single query declaration. The method-name included for a query-method must match the declaration in the home interface and not the bean class. This just means that the entries in the deployment descriptor must start with find and not ejbFind . The ejb-ql entry then defines a corresponding query to be executed whenever the finder is called. You'll learn the syntax for these queries in Chapter 8. In this example, the first two queries correspond to finder methods that locate all auctions and locate all nonpending auctions, respectively.

Note

You're not required to declare the findByPrimaryKey method in the deployment descriptor because the container automatically provides an implementation for that finder when you're using CMP.


You define select method queries in the deployment descriptor using the same syntax used for finder methods. The only difference is that you use the query-method element to identify a select method declared in the bean class (as an abstract method) instead of a finder method declared in the home interface. The naming restrictions imposed on these two method types make it obvious to the container which type of query method you're defining. Unlike finder methods, the method-name given for a select method must exactly match the method name in your bean class. Every method-name specified for a select method must begin with ejbSelect . In the preceding example, the query entry for ejbSelectAuctionedItems defines the statement used to satisfy the select method of the same name declared in EnglishAuctionCMPBean .

Mapping the Abstract Persistence Schema to a Database

When it's time to map an entity bean's abstract persistence schema to a database (or other data store), the deployer becomes dependent on the tools specific to the container. These tools usually produce vendor-specific deployment descriptors that are used along with the ejb-jar deployment descriptor to deploy an entity. For example, Listing 7.4 and Listing 7.5 show excerpts from the two descriptors used by WebLogic to deploy CMP entity beans.

Listing 7.4 weblogic-ejb-jar.xml “A Vendor-Specific Deployment Descriptor Identifies the CMP Implementation
 <?xml version="1.0"?>  <!DOCTYPE weblogic-ejb-jar PUBLIC    '-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN'    'http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd'>  <weblogic-ejb-jar>    <weblogic-enterprise-bean>      <ejb-name>EnglishAuction</ejb-name>      <entity-descriptor>        <entity-cache>          <max-beans-in-cache>100</max-beans-in-cache>        </entity-cache>        <persistence>          <persistence-type>            <type-identifier>WebLogic_CMP_RDBMS</type-identifier>            <type-version>6.0</type-version>            <type-storage>META-INF/weblogic-cmp-rdbms-jar.xml</type-storage>          </persistence-type>          <persistence-use>            <type-identifier>WebLogic_CMP_RDBMS</type-identifier>            <type-version>6.0</type-version>          </persistence-use>        </persistence>      </entity-descriptor>      <reference-descriptor>        <ejb-local-reference-description>          <ejb-ref-name>ejb/AuctionBid</ejb-ref-name>          <jndi-name>AuctionBid</jndi-name>        </ejb-local-reference-description>      </reference-descriptor>      <jndi-name>EnglishAuctionRemote</jndi-name>      <local-jndi-name>EnglishAuction</local-jndi-name>    </weblogic-enterprise-bean>    ...  </weblogic-ejb-jar> 
Listing 7.5 weblogic-cmp-rdbms-jar.xml “A Vendor-Specific Deployment Descriptor Maps an Entity Bean to a Database
 <?xml version="1.0"?>  <!DOCTYPE weblogic-rdbms-jar PUBLIC   '-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB RDBMS Persistence//EN'   'http://www.bea.com/servers/wls600/dtd/weblogic-rdbms20-persistence-600.dtd'>  <weblogic-rdbms-jar>    <weblogic-rdbms-bean>      <ejb-name>EnglishAuction</ejb-name>      <data-source-name>auctionSource</data-source-name>      <table-name>auction</table-name>      <field-map>        <cmp-field>idField</cmp-field>        <dbms-column>id</dbms-column>      </field-map>      <field-map>        <cmp-field>nameField</cmp-field>        <dbms-column>Name</dbms-column>      </field-map>      ...      <field-map>        <cmp-field>quantityField</cmp-field>        <dbms-column>Quantity</dbms-column>      </field-map>      <automatic-key-generation>        <generator-type>NAMED_SEQUENCE_TABLE</generator-type>        <generator-name>auctionseq</generator-name>        <key-cache-size>10</key-cache-size>      </automatic-key-generation>    </weblogic-rdbms-bean>    <weblogic-rdbms-bean>      <ejb-name>AuctionBid</ejb-name>      <data-source-name>auctionSource</data-source-name>      <table-name>Bid</table-name>      <field-map>        <cmp-field>idField</cmp-field>        <dbms-column>id</dbms-column>      </field-map>      ...      <field-map>        <cmp-field>transactionIdField</cmp-field>        <dbms-column>TransactionId</dbms-column>      </field-map>      <automatic-key-generation>        <generator-type>NAMED_SEQUENCE_TABLE</generator-type>        <generator-name>bidseq</generator-name>        <key-cache-size>10</key-cache-size>      </automatic-key-generation>    </weblogic-rdbms-bean>    <weblogic-rdbms-bean>      <ejb-name>Bidder</ejb-name>      ...    </weblogic-rdbms-bean>    <weblogic-rdbms-bean>      <ejb-name>StreetAddress</ejb-name>      ...    </weblogic-rdbms-bean>    <weblogic-rdbms-bean>      <ejb-name>Item</ejb-name>      ...    </weblogic-rdbms-bean>    <weblogic-rdbms-relation>      <relation-name>EnglishAuction-LeadingBid</relation-name>      <weblogic-relationship-role>        <relationship-role-name>auction-has-a-leading-bid </relationship-role-name>        <column-map>          <foreign-key-column>LeadingBidId</foreign-key-column>          <key-column>id</key-column>        </column-map>      </weblogic-relationship-role>    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>EnglishAuction-WinningBid</relation-name>      ...    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>EnglishAuction-Item</relation-name>      <weblogic-relationship-role>        <relationship-role-name>auction-offers-item</relationship-role-name>        <column-map>          <foreign-key-column>ItemId</foreign-key-column>          <key-column>id</key-column>        </column-map>      </weblogic-relationship-role>    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>EnglishAuction-AuctionBid</relation-name>      <weblogic-relationship-role>        <relationship-role-name>bid-belongs-to-auction</relationship-role-name>        <column-map>          <foreign-key-column>AuctionId</foreign-key-column>          <key-column>id</key-column>        </column-map>      </weblogic-relationship-role>    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>Bidder-BillingAddress</relation-name>      <weblogic-relationship-role>        <relationship-role-name>            bidder-has-a-billing-address        </relationship-role-name>        <column-map>          <foreign-key-column>BillingAddressId</foreign-key-column>          <key-column>id</key-column>        </column-map>      </weblogic-relationship-role>    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>Bidder-ShippingAddress</relation-name>      ...    </weblogic-rdbms-relation>    <weblogic-rdbms-relation>      <relation-name>Bidder-AuctionBid</relation-name>      <weblogic-relationship-role>        <relationship-role-name>bid-submitted-by-bidder</relationship-role-name>        <column-map>          <foreign-key-column>BidderId</foreign-key-column>          <key-column>id</key-column>        </column-map>      </weblogic-relationship-role>    </weblogic-rdbms-relation>  </weblogic-rdbms-jar> 

Beyond what you've seen in earlier BMP examples, the descriptor in Listing 7.4 does nothing more than identify the CMP implementation being used by the application. The file in Listing 7.5 associates the auction example entity beans with a particular data source and maps each CMP field to a particular table and column found within that data source. Each relationship also is qualified with entries that identify the foreign key and primary key column pairs. In defining the relationships, each relation-name must match an ejb-relation- name in the ejb-jar.xml file and each relationship-role-name must match an ejb-relationship-role-name .

Listing 7.5 also shows an example of selecting a primary key generation option. The automatic-key-generation entries for EnglishAuction and AuctionBid identify the sequence tables to be used by the container. To use the same sequence tables used for the BMP version, you need to change the name of the next_id column to SEQUENCE . Other vendors offer the same type of options for primary keys, so check your documentation to see what you have available.

Container Implementation of a CMP Bean

When you run your container vendor's tools to prepare a CMP bean for deployment, a concrete implementation class for the bean is created. A vendor is free to choose how to do this, but the deployment tools must create a subclass of your bean that provides concrete implementations of your abstract methods. Based on the vendor-specific deployment descriptor entries you provide, this class is dynamically created with the knowledge it needs to perform all the required interactions with the data store. A large part of this consists of providing implementations for the callback methods and any finder and select methods that you've declared.

Given that vendors have unique approaches for implementing a CMP bean, there's not a lot of general discussion that applies to these classes. However, if you're the curious type, you might be interested in seeing what the source code for one looks like. Listing 7.6 shows parts of the implementation class generated for the EnglishAuctionCMPBean class by WebLogic's ejbc tool.

Listing 7.6 WebLogic Implementation Class for a CMP Entity Bean
 /**   * This code was automatically generated at 6:34:13 PM on Jul 16, 2001   * by weblogic.ejb20.cmp.rdbms.codegen.RDBMSCodeGenerator -- do not edit.   *   * @version unknown   * @author Copyright  2001 by BEA Systems, Inc. All Rights Reserved.   */  package com.que.ejb20.auction.model;  ...  public class EnglishAuction_WebLogic_CMP_RDBMS    extends com.que.ejb20.auction.model.EnglishAuctionCMPBean    implements CMPBean  {   ...    // Instance variable(s)    ...    public java.lang.Integer idField;    public java.lang.String nameField;    public java.lang.String descriptionField;    public java.lang.String statusField;    public java.lang.Double startingBidField;    public java.lang.Double minBidIncrementField;    public java.lang.Double reserveAmountField;    public java.sql.Timestamp startDateTimeField;    public java.sql.Timestamp scheduledEndDateTimeField;    public java.sql.Timestamp actualEndDateTimeField;    public java.lang.Integer quantityField;    ...    // Getter and Setter methods.    ...    public java.lang.String getNameField()    {     ...        return nameField;      ...    }    public void setNameField(java.lang.String nameField)    {     this.nameField = nameField;      ...    }    ...    public com.que.ejb20.auction.model.AuctionBid getLeadingBid() {     try {       if (!__WL_isLoaded[11]) {         __WL_loadGroup0();        }        if (__WL_leadingBid_field_==null) {         if (!(__WL_leadingBid_idField==null))            __WL_leadingBid_field_ = (com.que.ejb20.auction.model.AuctionBid)              __WL_leadingBid_bm.localFindByPrimaryKey(__WL_leadingBid_finder_,                this.__WL_leadingBid_idField);        }        return __WL_leadingBid_field_;      } catch (RuntimeException re) {       ...      } catch (Exception ex) {       ...      }    }    public void setLeadingBid(com.que.ejb20.auction.model.AuctionBid leadingBid) {     if (__WL_method_state==STATE_EJB_CREATE) {       throw new IllegalStateException("The setXXX method for a cmr-field may not be graphics/ccc.gif called during ejbCreate. The setXXX method should be called during ejbPostCreate instead. graphics/ccc.gif ");      }      try {       ...        __WL_setNullLeadingBid(false);        __WL_doSetLeadingBid(leadingBid);        __WL_postSetLeadingBid();      } catch (RuntimeException re) {       ...      } catch (Exception ex) {       ...      }    }    ...    //Finder methods.    ...    public java.util.Collection ejbFindNonPendingAuctions()      throws javax.ejb.FinderException    {     ...      java.sql.Connection __WL_con = null;      java.sql.PreparedStatement __WL_stmt = null;      java.sql.ResultSet __WL_rs = null;      try {       __WL_con = __WL_pm.getConnection();      } catch (java.lang.Exception e) {       ...      }      try {       java.lang.String __WL_query = "SELECT WL0.ActualEndDate, WL0.Description, WL0.id, graphics/ccc.gif WL0.MinBidIncrement, WL0.Name, WL0.Quantity, WL0.ReserveAmount, WL0.ScheduledEndDate, WL0. graphics/ccc.gif StartDate, WL0.StartingBid, WL0.Status, WL0.ItemId, WL0.LeadingBidId, WL0.WinningBidId graphics/ccc.gif FROM auction WL0 WHERE (WL0.Status <> 'Pending')"  + __WL_pm.selectForUpdate();        ...        __WL_stmt = __WL_con.prepareStatement(__WL_query);        ...        __WL_rs = __WL_stmt.executeQuery();      } catch (java.lang.Exception e) {       ...      }      try {       java.util.Collection __WL_collection = new java.util.ArrayList();        ...        return __WL_collection;      } catch (java.sql.SQLException sqle) {       ...      } catch (java.lang.Exception e) {       ...      } finally {       ...      }    }    ...    //Home methods.    public java.util.Collection ejbHomeGetItemsBeingAuctioned()    {     ...        result =  super.ejbHomeGetItemsBeingAuctioned();        return result;      ...    }    ...  } 

The first point to notice about Listing 7.6 is that the generated class is declared to extend EnglishAuctionCMPBean . You then can see that, based on the abstract methods in the auction class and the CMP fields defined in the deployment descriptor, instance variables are declared for each field that needs to be persisted . Each of these fields is accessed using concrete implementations of the corresponding get and set methods. The get and set methods for managing the CMR fields are each implemented as well. The final portion of the source included in the listing shows an example finder method implementation. In this case, a SQL statement was generated based on the EJB QL query declaration in the deployment descriptor and the corresponding table and column information. Listing 7.6 includes only a fraction of the generated code for this bean, but it should give you a feel for what the container has to provide.

Testing the Auction Example

The source code included on the CD-ROM includes the CMP implementation for the auction classes and the complete deployment descriptors. You can use the same EntityBeanClient class introduced in Chapter 6 to test the auction entity bean. Because the interfaces to the bean stayed the same, the example works the same under CMP as it did for BMP. The only difference is that the deployment descriptors swap the implementation classes and include the necessary CMP declarations.



Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net