Download PDF Home History |  | API Search Feedback FAQ

> ## Advanced CMP Topics: The OrderApp Example

> The `OrderApp` application is an advanced CMP example. It contains entity beans that have self-referential relationships, one-to-one relationships, unidirectional relationships, unknown primary keys, primitive primary key types, and composite primary keys.

> ### Structure of OrderApp

> `OrderApp` is a simple inventory and ordering application for maintaining a catalog of parts and placing an itemized order of those parts. It has entity beans that represent parts, vendors, orders, and line items. These entity beans are accessed using a stateful session bean that holds the business logic of the application. A simple command-line client adds data to the entity beans, manipulates the data, and displays data from the catalog.

> The information contained in an order can be divided into different elements. What is the order number? What parts are included in the order? What parts make up that part? Who makes the part? What are the specifications for the part? Are there any schematics for the part? `OrderApp` is a simplified version of an ordering system that has all these elements.

> This example assumes that you have successfully built, assembled, and deployed the `RosterApp` example application and that you are familiar with assembling entity beans in `deploytool`.

> `OrderApp` consists of three modules: `DataRegistryJAR`, an enterprise bean JAR file containing the entity beans, the support classes, and the database schema file; `RequestJAR`, an enterprise bean JAR containing a stateful session bean that accesses the data in the entity beans; and `OrderAppClient`, the application client that populates the entity beans with data and manipulates the data, displaying the results in a terminal.

> Figure 27-10 shows `OrderApp`'s database tables.

> Figure 27-10 Database Tables in `OrderApp`

> ### Bean Relationships in OrderApp

> The `RosterApp` example application shows how to set up one-to-many and many-to-many relationships between entity beans. `OrderApp` demonstrates two additional types of entity bean relationships (see Figure 27-11): one-to-one and self-referential relationships.

> Figure 27-11 Relationships between Entity Beans in `OrderApp`

> #### Self-Referential Relationships

> A self-referential relationship is a relationship between container-managed relationship fields (CMR) in the same entity bean. `PartBean` has a CMR field `bomPart` that has a one-to-many relationship with the CMR field `parts`, which is also in `PartBean`. That is, a part can be made up of many parts, and each of those parts has exactly one bill-of-material part.

> The primary key for `PartBean` is a compound primary key, a combination of the `partNumber` and `revision` fields. It is mapped to the `PART_NUMBER` and `REVISION` columns in the `PART` table.

> #### One-to-One Relationships

> `PartBean` has a CMR field, `vendorPart`, that has a one-to-one relationship with `VendorPartBean`'s CMR field `part`. That is, each part has exactly one vendor part, and vice versa.

> #### One-to-Many Relationship Mapped to Overlapping Primary and Foreign Keys

> `OrderBean` has a CMR field, `lineItems`, that has a one-to-many relationship with `LineItemBean`'s CMR field `order`. That is, each order has one or more line item.

> `LineItemBean` uses a compound primary key that is made up of the `orderId` and `itemId` fields. This compound primary key maps to the `ORDER_ID` and `ITEM_ID` columns in the `LINEITEM` database table. `ORDER_ID` is a foreign key to the `ORDER_ID` column in the `ORDERS` table. This means that the `ORDER_ID` column is mapped twice: once as a primary key field, `orderId`; and again as a relationship field, `order`.

> #### Unidirectional Relationships

> `LineItemBean` has a CMR field, `vendorPart`, that has a unidirectional many-to-one relationship with `VendorPartBean`. That is, there is no CMR field in the target entity bean in this relationship.

> ### Primary Keys in OrderApp's Entity Beans

> The `OrderApp` example uses more complicated primary keys than does `RosterApp`.

> #### Unknown Primary Keys

> In `OrderApp`, `VendorPartBean` uses an unknown primary key. That is, the enterprise bean does not specify primary key fields and uses `java.lang.Object` as the primary key class. See The Primary Key Class for more information on primary keys.

> #### Primitive Type Primary Keys

> `VendorBean` uses a primary key that is a Java programming language primitive type, an `int`. To use a primitive type as the primary key, you must create a wrapper class. `VendorKey` is the wrapper class for `VendorBean`.

> The wrapper primary key class has the same requirements as described in The Primary Key Class. This is the `VendorKey` wrapper class:

>     package dataregistry;
>     public final class VendorKey implements java.io.Serializable {

>       public int vendorId;

>       public boolean equals(Object otherOb) {

>         if (this == otherOb) {
>           return true;
>         }
>         if (!(otherOb instanceof VendorKey)) {
>           return false;
>         }
>         VendorKey other = (VendorKey) otherOb;
>         return (vendorId == other.vendorId);
>       }
>       public int hashCode() {
>         return vendorId;
>       }
>       public String toString() {
>         return "" + vendorId;
>       }
>     }

> #### Compound Primary Keys

> A compound primary key is made up of multiple fields and follows the requirements described in The Primary Key Class. To use a compound primary key, you must create a wrapper class.

> In `OrderApp`, two entity beans use compound primary keys: `PartBean` and `LineItemBean`.

> `PartBean` uses the `PartKey` wrapper class. `PartBean`'s primary key is a combination of the part number and the revision number. `PartKey` encapsulates this primary key.

> `LineItemBean` uses the `LineItemKey` class. `LineItemBean`'s primary key is a combination of the order number and the item number. `LineItemKey` encapsulates this primary key. This is the `LineItemKey` compound primary key wrapper class:

>     package dataregistry;

>     public final class LineItemKey implements
>           java.io.Serializable {

>       public Integer orderId;
>       public int itemId;

>       public boolean equals(Object otherOb) {
>         if (this == otherOb) {
>           return true;
>         }
>         if (!(otherOb instanceof LineItemKey)) {
>           return false;
>         }
>         LineItemKey other = (LineItemKey) otherOb;
>         return ((orderId==null?other.orderId==null:orderId.equals
>             (other.orderId)) && (itemId == other.itemId));
>       }

>       public int hashCode() {
>         return ((orderId==null?0:orderId.hashCode())
>             ^ ((int) itemId));
>       }

>       public String toString() {
>         return "" + orderId + "-" + itemId;
>       }
>     }

> ### Entity Bean Mapped to More Than One Database Table

> `PartBean`'s fields map to more than one database table: `PART` and `PART_DETAIL`. The `PART_DETAIL` table holds the specification and schematics for the part. When you set up the container-managed fields and relationships in `deploytool`, you will add `PART_DETAIL` as a secondary table for `PartBean`.

> ### Finder and Selector Methods

> `VendorBean` has two finder methods: `findByPartialName` and `findByOrder`. The `findByPartialName` method searches through the vendor list for matches to a partial name. `findByOrder` finds all vendors for a particular order.

> `LineItemBean` has one finder method, `findAll`, which finds all line items.

> `OrderBean` has one selector method, `ejbSelectAll`, which returns all orders.

> `VendorPartBean` has two selector methods. `ejbSelectAvgPrice` returns the average price of all parts from a vendor. `ejbSelectTotalPricePerVendor` returns the price of all the parts from a particular vendor.

> Selector methods cannot be accessed outside a bean instance because the selector methods are not defined in the bean interface. If you are using a selector method to return data to a caller, the selector method must be called from a home or business method. In `OrderApp`, the `LocalVendorPartHome.getAvgPrice` method returns the result of the `ejbSelectAvgPrice` method in `VendorPartBean`.

> The return type of a selector query is usually defined by the return type of the `ejbSelect` methods. You must specify the return type as `Remote` if the method returns a remote interface or a `java.util.Collection` of remote interfaces. If the return type is a local interface or a `java.util.Collection` of local interfaces, set the return type to `Local`. If the return type is neither a local nor a remote interface, nor a collection of local or remote interfaces, do not set the return type (in `deploytool`, set the return type to `None`). The `OrderBean.ejbSelectAll` method returns a collection of local interfaces. `VendorPartBean.ejbSelectAvgPrice` and `VendorPartBean.ejbSelectTotalPricePerVendor` return a `Double`, so the return type is set to `None`.

> ### Using Home Methods

> Home methods are defined in the home interface of a bean and correspond to methods named `ejbHome<``METHOD``>` in the bean class. For example, a method `getValue`, defined in the `LocalExampleHome` interface, corresponds to the `ejbHomeGetValue` method implemented in `ExampleBean`. The `ejbHome<``METHOD``>` methods are implemented by the bean developer.

> `OrderApp` uses three home methods: `LocalOrderHome.adjustDiscount`, `LocalVendorPartHome.getAvgPrice`, and `LocalVendorPartHome.getTotalPricePerVendor`. Home methods operate on all instances of a bean rather than on any particular bean instance. That is, home methods cannot access the container-managed fields and relationships of a bean instance on which the method is called.

> For example, `LocalOrderHome.adjustDiscount` is used to increase or decrease the discount on all orders.

> ### Cascade Deletes in OrderApp

> Entity beans that use container-managed relationships often have dependencies on the existence of the other bean in the relationship. For example, a line item is part of an order, and if the order is deleted, then the line item should also be deleted. This is called a cascade delete relationship.

> In `OrderApp`, there are two cascade delete dependencies in the bean relationships. If the `OrderBean` to which a `LineItemBean` is related is deleted, then the `LineItemBean` should also be deleted. If the `VendorBean` to which a `VendorPartBean` is related is deleted, then the `VendorPartBean` should also be deleted.

> ### BLOB and CLOB Database Types in OrderApp

> The `PART_DETAIL` table in the database has a column, `DRAWING`, of type `BLOB`. `BLOB` stands for binary large objects, which are used for storing binary data such as an image. The `DRAWING` column is mapped to the container-managed field `PartBean`. `drawing` of type `java.io.Serializable`.

> `PART_DETAIL` also has a column, `SPECIFICATION`, of type `CLOB`. `CLOB` stands for character large objects, which are used to store string data too large to be stored in a `VARCHAR` column. `SPECIFICATION` is mapped to the container-managed field `PartBean.specification` of type `java.lang.String`.

> Note: You cannot use a `BLOB` or `CLOB` column in the `WHERE` clause of a finder or selector EJB QL query.

> ### Building and Running the OrderApp Example

> This section assumes that you are familiar with how to package entity beans in `deploytool` as described in Building and Running the RosterApp Example, have started the PointBase server, and have created the JDBC resource.

> #### Create the Database Tables

> To create the database tables, do the following:

> 1. In a terminal navigate to

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/`

> 2. Enter the following command:

> `asant create-db_common`

> #### Capture the Database Schema

> To capture the database schema, do the following:

> 1. In a terminal navigate to

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/`

> 2. Enter the following command:

> `asant capture-db-schema`

> #### Build the Application

> To build the application components of `OrderApp`, do the following:

> 1. Navigate to

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/`

> 2. Enter the following command:

> `asant build`

> #### Package the Application

> You will now package the enterprise beans, support classes, database schema, and client class in `deploytool`. This section assumes that you are familiar with how to package these application modules in `deploytool`.

> ##### Create the Application Modules

> 1. Create a new application in `deploytool` named `OrderApp` in

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/`

> 2. Create an enterprise bean JAR named `RequestJAR` that contains the files in

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/build/
> request/`

> 3. Set up a stateful session bean, `RequestBean`, in `RequestJAR` with a remote home interface of `request.RequestHome` and a remote interface of `request.Request`.
> 4. Create an enterprise bean JAR named `DataRegistryJAR` that contains the files in

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/build/
> dataregistry`

> And the database schema file:

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/build/
> cmporder.dbschema`

> 5. Set up the entity beans (`LineItemBean`, `OrderBean`, `PartBean`, `VendorBean`, and `VendorPartBean`) according to Table 27-2 through Table 27-6.

>    Table 27-2 Settings for LineItemBean
>    Setting | Value
>    --- | ---
>    Local Home Interface | `dataregistry.LocalLineItemHome`
>    Local Interface | `dataregistry.LocalLineItem`
>    Persistent Fields | `orderId, itemId, quantity`
>    Abstract Schema Name | `LineItem`
>    Primary Key Class | User-defined class `dataregistry.LineItemKey`

>    Table 27-3 Settings for OrderBean
>    Setting | Value
>    --- | ---
>    Local Home Interface | `dataregistry.LocalOrderHome`
>    Local Interface | `dataregistry.LocalOrder`
>    Persistent Fields | `status, orderId, discount, lastUpdate, shipmentInfo`
>    Abstract Schema Name | `Order`
>    Primary Key Class | Existing field `orderId`

>    Table 27-4 Settings for PartBean
>    Setting | Value
>    --- | ---
>    Local Home Interface | `dataregistry.LocalPartHome`
>    Local Interface | `dataregistry.LocalPart`
>    Persistent Fields | `description, partNumber, revision, revisionDate, drawing, specification`
>    Abstract Schema Name | `Part`
>    Primary Key Class | User-defined class `dataregistry.PartKey`

>    Table 27-5 Settings for VendorBean
>    Setting | Value
>    --- | ---
>    Local Home Interface | `dataregistry.LocalVendorHome`
>    Local Interface | `dataregistry.LocalVendor`
>    Persistent Fields | `address, name, vendorId, contact, phone`
>    Abstract Schema Name | `Vendor`
>    Primary Key Class | User-defined class `dataregistry.VendorKey`

>    Table 27-6 Settings for VendorPartBean
>    Setting | Value
>    --- | ---
>    Local Home Interface | `dataregistry.LocalVendorPartHome`
>    Local Interface | `dataregistry.LocalVendorPart`
>    Persistent Fields | `description, price`
>    Abstract Schema Name | `VendorPart`
>    Primary Key Class | Unknown Primary Key Class

> ##### Configure the Entity Bean Relationships

> Now we'll configure the relationships of the entity beans and map the fields and relationships to the database tables.

> 1. Set up the bean relationships according to Table 27-7:

>    Table 27-7 OrderApp Bean Relationships
>    Multi-plicity | Bean A | Field Referencing Bean B and Field Type | Delete When Bean B Is Deleted? | Bean B | Field Referencing Bean A and Field Type | Delete When Bean A Is Deleted?
>    --- | --- | --- | --- | --- | --- | ---
>    *:1 | `PartBean` | `bomPart` |  | `PartBean` | `parts`, `java.util. Collection` |
>    1:* | `OrderBean` | `lineItems`, `java.util. Collection` |  | `Line ItemBean` | `order` | Yes
>    *:1 | `Vendor PartBean` | `vendor` | Yes | `Vendor Bean` | `vendorParts`, `java.util. Collection` |
>    1:1 | `Vendor PartBean` | `part` |  | `PartBean` | `vendorPart` |
>    *:1 | `Line ItemBean` | `vendorPart` |  | `Vendor PartBean` | `<none>` |

> 2. Set the JNDI Name of the CMP Resource to `jdbc/ejbTutorialDB`.
> 3. Create the database mappings using the `cmporder.dbschema` file in the Sun-specific Settings dialog box, CMP Database view.
> 4. Manually map `OrderBean` to the `ORDERS` database table in the Sun-specific Settings dialog box, CMP Database view:
> 1. Select `OrderBean` in the Enterprise Bean field under Persistent Field Mappings.
> 2. Select `ORDERS` in the Primary Table drop-down.

> `ORDER` is a reserved keyword in SQL, so the table name is `ORDERS`.

> 5. Map `PartBean` to the `PART` and `PART_DETAIL` database tables:
> 1. Select `PartBean` in the Enterprise Bean field under Persistent Field Mappings.
> 2. Click Advanced Settings under Mappings for Bean `PartBean`.
> 3. Click Add.
> 4. In the Secondary Table field select `PART_DETAIL`.
> 5. Select `PART_NUMBER` in the Primary Table Column.
> 6. Select `PART_NUMBER` in the Secondary Table Column.
> 7. Click Add Pair.
> 8. Select `REVISION` in the Primary Table Column.
> 9. Select `REVISION` in the Secondary Table Column.
> 10. Click OK.
> 11. Click OK.
> 6. Click Automap All to automatically map the fields and relationships to the database tables. Repeat this step for all the entity beans until all the relationships and fields are mapped.
> 7. Click Close.

> ##### Add the Finder and Selector Queries

> Add the finder and selector queries to the entity beans as listed in Table 27-8 and Table 27-9:

> Table 27-8 Finder Queries in OrderApp
> Enterprise Bean | Method | EJB QL Query
> --- | --- | ---
> `VendorBean` | `findByOrder` | `SELECT DISTINCT l.vendorPart.vendor FROM Order o, IN(o.lineItems) AS l WHERE o.orderId = ?1 ORDER BY l.vendorPart.vendor.name`
> `VendorBean` | `findByPartialName` | `SELECT OBJECT(v) FROM Vendor v WHERE LOCATE(?1, v.name) > 0`
> `LineItemBean` | `findAll` | `SELECT OBJECT(l) FROM LineItem l`

> Table 27-9 Selector Queries in OrderApp
> Enterprise Bean | Method | EJB QL Query | Return EJB Type
> --- | --- | --- | ---
> `OrderBean` | `ejbSelectAll` | `SELECT OBJECT(o) FROM Order o` | Local
> `VendorPartBean` | `ejbSelectAvgPrice` | `SELECT AVG(vp.price) FROM VendorPart vp` | None
> `VendorPartBean` | `ejbSelectTotal PricePerVendor` | `SELECT SUM(vp.price) FROM VendorPart vp WHERE vp.vendor.vendorId = ?1` | None

> Note: The queries are included in the `cmporderQueries.txt` file, located in `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/` to make it easier to enter the queries.

> ##### Set the Transaction Attributes

> The transactions for all our enterprise beans (`RequestBean`, `LineItemBean`, `OrderBean`, `PartBean`, `VendorBean`, and `VendorPartBean`) must be managed by the container.

> 1. Select the enterprise bean in `deploytool`.
> 2. Select the Transactions tab.
> 3. Select Container-Managed under Transaction Management. All transaction attributes for the bean's methods will automatically be set to `Required`.

> ##### Set RequestBean's Enterprise Bean References

> `RequestBean` accesses the local entity beans contained in `DataRegistryJAR`. You must set the references to the entity beans in `RequestBean`.

> 1. Select `RequestBean` in `RequestJAR`.
> 2. Click the EJB Ref's tab.
> 3. Enter the references according to Table 27-10. All the references are to local entity beans.

>    Table 27-10 Enterprise Bean References in RequestBean
>    Coded Name | Home Interface | Local Interface | Target Enterprise Bean Name
>    --- | --- | --- | ---
>    `ejb/SimpleLineItem` | `dataregistry. LocalLineItemHome` | `dataregistry. LocalLineItem` | `LineItemBean`
>    `ejb/SimpleVendorPart` | `dataregistry. LocalVendorPart Home` | `dataregistry. LocalVendorPart` | `VendorPartBean`
>    `ejb/SimpleOrder` | `dataregistry. LocalOrderHome` | `dataregistry. LocalOrder` | `OrderBean`
>    `ejb/SimplePart` | `dataregistry. LocalPartHome` | `dataregistry. LocalPart` | `PartBean`
>    `ejb/SimpleVendor` | `dataregistry. LocalVendorHome` | `dataregistry. LocalVendor` | `VendorBean`

> ##### Package the Application Client

> Now we'll add the application client to the EAR.

> 1. Create a new application client in `OrderApp` named `OrderAppClient`.
> 2. Add the contents of the following directory:

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/build/
> client/`

> 3. Set the main class of the client to `client.Client`.
> 4. Set the enterprise bean reference for the client:
> 1. Set the Coded Name to `ejb/Request`.
> 2. Set the EJB Type to `Session`.
> 3. Set the Interfaces to `Remote`.
> 4. Set the Home Interface to `request.RequestHome`.
> 5. Set the Remote Interface to `request.Request`.
> 6. Enter `RequestBean` in the JNDI Name field under Target EJB.
> 7. Click OK.

> #### Deploy the Enterprise Application

> `OrderApp` is now ready to be deployed:

> 1. Select FileSave.
> 2. Select `OrderApp` in `deploytool`.
> 3. Select ToolsDeploy.
> 4. Check Return Client Jar in the Deploy Module dialog box.

> #### Run the Client Application

> The client application accesses the `RequestBean` session bean, which in turn manipulates data in `OrderApp`'s entity beans.

> Note: This example will perform poorly compared with a well-designed CMP application. `OrderApp` is designed primarily for instructional purposes, and does not follow the best practices recommendations as outlined in the book Designing Enterprise Applications with the J2EE Platform, Second Edition, Inderjeet Singh et al., (Addison-Wesley, 2002).

> To run the client, follow these steps:

> 1. In a terminal, go to

> `<``INSTALL``>/j2eetutorial14/examples/ejb/cmporder/`

> 2. Enter the following command:

> `appclient -client OrderAppClient.jar`

> 3. You will see the following output in the terminal:

> `Cost of Bill of Material for PN SDFG-ERTY-BN Rev: 7: $241.86
> Cost of Order 1111: $664.68
> Cost of Order 4312: $2,011.44
> Adding 5% discount
> Cost of Order 1111: $627.75
> Cost of Order 4312: $1,910.87
> Removing 7% discount
> Cost of Order 1111: $679.45
> Cost of Order 4312: $2,011.44
> Average price of all parts: $117.55
> Total price of parts for Vendor 100: $501.06
> Ordered list of vendors for order 1111
> 200 Gadget, Inc. Mrs. Smith
> 100 WidgetCorp Mr. Jones
> Found 6 line items
> Removing Order
> Found 3 line items
> Found 1 out of 2 vendors with 'I' in the name:
> Gadget, Inc.`

> Note: Re-create the database tables using the `create-db_common` task before re-running the client.

Download PDF Home History |  | API Search Feedback FAQ

All of the material in The J2EE(TM) 1.4 Tutorial is copyright-protected and may not be published in other works without express written permission from Sun Microsystems.