Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Mastering Enterprise JavaBeans™ and the Java 2 Platform, Enterprise Edition - Roman E

..pdf
Скачиваний:
42
Добавлен:
24.05.2014
Размер:
6.28 Mб
Скачать

J2EE in the Real World: Implementing Our E- Commerce Entity Beans 371

security, and transaction attributes. The EJB container will inspect the deployment descriptor at runtime and will use the information to manage the bean. Our deployment descriptor is shown in Table 13.1.

Notice that we’ve enumerated the five public container-managed entity bean fields we defined in our bean. This is necessary so the container will know which fields it should manage when performing persistent operations, such as an ejbStore() or an ejbLoad().

There are also two transaction-oriented deployment descriptor settings in this example. First is a transaction attribute, which describes how our bean should be enlisted in transactions. If you’ll recall, the possible settings here are the following:

TX_BEAN_MANAGED. The bean explicitly conducts transactions itself. This means you need to program transactional logic for demarcating transactional boundaries in the bean itself. This is the “traditional” (yet cumbersome) way of performing transactions in other middleware systems.

TX_NOT_SUPPORTED. The bean cannot participate in a transaction. Any current transactions are suspended during the invocation and then resumed afterward.

TX_REQUIRED. If a transaction is already going, the bean will join it. If not, the bean runs in its own new transaction.

Table 13.1 Deployment Descriptor Settings for CustomerBean

DEPLOYMENT

DESCRIPTOR SETTING

VALUE

Bean home name

Ecommerce.CustomerHome

Enterprise bean class name

com.wiley.compBooks.ecommerce.CustomerBean

Home interface class name

com.wiley.compBooks.ecommerce.CustomerHome

Remote interface class name

com.wiley.compBooks.ecommerce.Customer

Environment properties

<empty>

Re-entrant

false

Primary key class name

com.wiley.compBooks.ecommerce.CustomerPK

Container-managed fields

customerID, name, address, and password

Transaction isolation level

TRANSACTION_READ_UNCOMMITTED

Transaction attribute

TX_SUPPORTS

Run-as mode

CLIENT_IDENTITY

 

 

Go back to the first page for a quick link to buy this book online!

372 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

TX_REQUIRES_NEW. A new transaction must always occur during an invocation.

TX_SUPPORTS. If a transaction is already going, the bean will join it. If not, no transaction occurs.

TX_MANDATORY. If a transaction is already going, the bean will join it. If not, an exception is thrown.

We don’t anticipate that concurrent clients will manipulate instances of our Customer bean. Typically a Customer will be created once and only once, updates are rare, and it is unlikely that two concurrent users will simultaneously modify the same customer record. Therefore, we set a transaction mode of TX_SUPPORTS and an isolation level of TRANSACTION_READ_UNCOMMITTED. Of course, if this situation changes in the future, we can upgrade the deployment descriptor’s isolation level to suit any new needs.

In EJB 1.0, there is a small bug that prevents you from setting the TX_SUPPORTS transaction attribute. This bug applies only to TX_SUPPORTS, not the other attributes. This bug will also be fixed in future releases of EJB. For now, the workaround is to use a different isolation level, such as TX_REQUIRED.

Next, we have a security setting to have our bean run as the identity of the client. Since our bean will not be performing any secure operations, this mode is acceptable.

We also define a set of relationships between the container-managed fields and our underlying relational database. This step will vary from container to container because the EJB specification does not define how to map fields to an underlying data source. The field mapping is shown for the BEA WebLogic container in Table 13.2.

We also enumerate the logic of the finder methods that the container should implement. Again, this is also EJB container-specific and is shown for the BEA WebLogic container in Table 13.3.

Table 13.2 Persistent Settings for Our Customer Bean Assuming the BEA WebLogic Container

OBJECT/RELATIONAL SETTING

(ENTITY BEAN FIELD = RELATIONAL COLUMN NAME)

customerID=id

name=name

address=address

password=password

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Implementing Our E- Commerce Entity Beans 373

Table 13.3 Finder Semantics for Customer Bean Assuming the BEA WebLogic Container

FINDER SCRIPTING SYNTAX

“findByName(String name)” “(= name $name)”

“findByAddress(String address)” “(= address $address)”

“findAllCustomers()” “(= 1 1)”

The Order Line Item Entity Bean

Our next entity bean is a bean that models a line item of an order. If you recall from Chapter 12, an Order is a permanent record for goods purchased. Clients who connect to our Web site perform the following steps to create an Order:

1.Browse the catalog, adding Products to the user’s temporary Quote stateful session bean.

2.View the Quote on a separate screen, making any last-minute changes. Each distinct Product, along with the quantity of that Product that the user wants, is represented as a Quote Line Item.

3.Generate an Order from the Quote. Every Quote Line Item is converted into a permanent Order Line Item, which is a signal to manufacture goods.

Our Order Line Item entity bean contains information for a particular Product ordered. Why have Order Line Items, rather than simply aggregating Products in the Order entity bean? The answer is convenience of manipulation. With line items, our Pricer bean can compute discounts on a per-Product basis. The user also should be able to add and delete whole line items via the Web GUI we create. An order processing utility can inspect the line items one by one once they’re generated.

Our Line Items will model the following information:

■■The ID of this Order Line Item. This must be globally unique, and it will be our primary key.

■■The product that this Order Line Item represents. A manufacturing utility program can use this information to reveal which product to construct.

■■The quantity of the product that should be manufactured.

■■The discount that the Customer received on this Product. This is calculated with an external Pricer session bean, which we show in the following chapter.

More data, such as a separate billing address, could always be added later as needed.

Go back to the first page for a quick link to buy this book online!

374 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

OrderLineItem.java

Our remote interface is detailed in OrderLineItem.java, shown in Source 13.5.

The remote interface exposes methods to get and set the various fields we’ve identified. Most of the fields, such as the product, the discount, and the quantity, are settable. There are two exceptions:

■■There is no setter method for our line item’s unique ID because the ID is a permanent part of our line item, which is set on initialization.

■■The base price of the product is not settable—it’s extracted automatically from the Product bean.

package com.wiley.compBooks.ecommerce;

import javax.ejb.*;

import java.rmi.RemoteException;

/**

*These are the business logic methods exposed pubicly

*by OrderLineItemBean.

*

*This interface is what clients operate on when they

*interact with beans. The container vendor will

*implement this interface; the implementation object

*is called the EJB Object, which delegates

*invocations to the actual bean.

*/

public interface OrderLineItem extends EJBObject {

// Getter/setter methods for Entity Bean fields

public Product getProduct() throws RemoteException;

public void setProduct(Product product) throws RemoteException;

public double getBasePrice() throws RemoteException;

public double getDiscount() throws RemoteException;

public void setDiscount(double discount) throws RemoteException;

public int getQuantity() throws RemoteException;

public void setQuantity(int quantity) throws RemoteException;

}

Source 13.5 OrderLineItem.java

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Implementing Our E- Commerce Entity Beans 375

OrderLineItemBean.java

The implementation of our line-item is in OrderLineItemBean.java, shown in Source 13.6.

Most of this bean is fairly standard. We have a number of container-managed fields, such as the quantity and discount. They are initialized upon ejbCreate() and are automatically saved to and loaded from the database by the container. As with most container-managed persistent entity beans, our EJB-required methods have fairly trivial implementations.

Notice also that this is our first bean that has a relationship with other entity beans. But this is not as easy as it sounds, and it raises many issues. We examine this further in the following section.

package com.wiley.compBooks.ecommerce;

import java.sql.*; import javax.naming.*; import javax.ejb.*; import java.util.*;

import java.rmi.RemoteException; import javax.naming.*;

/**

*This is a container-managed persistent entity bean. It

*represents an order line item. A line item is an order

*for a quantity of a single product. Many line items

*together form an entire order.

*/

public class OrderLineItemBean implements EntityBean {

protected EntityContext ctx;

//------------------------------------------------

// Begin Container-Managed fields //------------------------------------------------

/*

*The id number of this line item. This is our

*primary key as well.

*/

public String orderLineItemID;

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!

376 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

/*

*These fields are:

*- The product that has been purchased.

*- The order that this line item is part of.

*Product information is encapsulated in a separate

*enterprise bean, called ProductBean, with an EJB

*Object called Product.

*

*Order information is encapsulated in a separate

*enterprise bean, called OrderBean, with an EJB

*Object called Order.

*

*Unfortunately, EJB 1.0 does not mandate that

*Containers persist references to EJB Objects.

*We must persist these fields as serializable

*primary keys, rather than as EJB Objects. Yet

*we still want to work with EJB Objects so that

*we can call methods on them. Hence, we must

*keep two sets of fields:

*

*- The productPK field is our Product's Primary

*Key, and the orderPK field is our Order's

*Primary Key. These are persistable

*container-managed fields.

*

*- The product field is our Product's EJB Object,

*and the order field is our Order's EJB Object.

*These are not persistent container-managed

*fields, but rather are there for convenience,

*so we can call methods on them.

*

*/

public String productPK; public String orderPK; protected Product product; protected Order order;

/*

* The quantity of goods that should be ordered */

public int quantity;

/*

* The discount that this specific Customer gets */

public double discount;

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Implementing Our E- Commerce Entity Beans 377

//------------------------------------------------

// End Container-Managed fields //------------------------------------------------

//------------------------------------------------

// Begin business methods //------------------------------------------------

public OrderLineItemBean() {

System.out.println("New OrderLineItem Entity Bean Java Object " + "created by EJB Container.");

}

public Product getProduct() throws RemoteException { System.out.println("OrderLineItem.getProduct() called."); return product;

}

public void setProduct(Product product) throws RemoteException { System.out.println("OrderLineItem.setProduct() called."); this.product = product;

}

public int getQuantity() throws RemoteException { System.out.println("OrderLineItem.getQuantity() called."); return quantity;

}

public void setQuantity(int quantity) throws RemoteException { System.out.println("OrderLineItem.setQuantity() called."); this.quantity = quantity;

}

/**

*Returns the base price. The base price is the

*product's price times the quantity ordered. This

*figure does not take discounts into consideration. */

public double getBasePrice() throws RemoteException { System.out.println("OrderLineItem.getBasePrice() called."); return quantity * product.getBasePrice();

}

/**

*Returns the discount that the customer gets on

*this order.

*

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!

378 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

*Note: The discount is a whole number, not

*a percentage discount.

*/

public double getDiscount() throws RemoteException { System.out.println("OrderLineItem.getDiscount() called."); return discount;

}

/**

*Sets the discount that the customer gets on

*this order.

*

*Note: The discount is a whole number, not

*a percentage discount.

*/

public void setDiscount(double discount) throws RemoteException { System.out.println("OrderLineItem.setDiscount() called."); this.discount = discount;

}

//------------------------------------------------

// End business methods //------------------------------------------------

//------------------------------------------------

//Begin EJB-required methods. The methods below

//are called by the Container, and never called

//by client code.

//------------------------------------------------

/**

*Associates this Bean instance with a particular

*context. Once done, we can query the Context

*for environment info, such as Bean

*customizations via properties.

*/

public void setEntityContext(EntityContext ctx) throws RemoteException { System.out.println("OrderLineItem.setEntityContext called"); this.ctx = ctx;

}

/**

*Disassociates this Bean instance with a

*particular context environment.

*/

public void unsetEntityContext() throws RemoteException { System.out.println("OrderLineItem.unsetEntityContext called"); this.ctx = null;

}

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!

J2EE in the Real World: Implementing Our E- Commerce Entity Beans 379

/**

*Called directly after activating this bean

*instance. You should acquire needed

*resources in this method.

*/

public void ejbActivate() throws RemoteException { System.out.println("OrderLineItem.ejbActivate() called.");

}

/**

*Called directly before passivating this bean

*instance. Release any resources you acquired

*in ejbActivate() in this method.

*/

public void ejbPassivate() throws RemoteException { System.out.println("OrderLineItem.ejbPassivate () called.");

}

/**

*Updates the database to reflect the current

*values of this object.

*

*Since we're using Container-Managed

*Persistence, the Container will automatically

*save our public container-managed fields into

*the database. We should perform any

*necessary pre-processing here.

*/

public void ejbStore() throws RemoteException { System.out.println("OrderLineItem.ejbStore() called.");

/*

*Since the container persists primary keys only, we must

*convert our references to EJB Objects into primary keys.

*/

productPK = ((ProductPK)product.getPrimaryKey()).productID; orderPK = ((OrderPK)order.getPrimaryKey()).orderID;

}

/**

*Updates this object to reflect any changes to

*the database data.

*

*Since we're using Container-Managed

*Persistence, the Container will automatically

*set our public fields to the correct values.

*We then do post-processing here.

*/

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!

380 M A S T E R I N G E N T E R P R I S E J A V A B E A N S

public void ejbLoad() throws RemoteException { System.out.println("OrderLineItem.ejbLoad() called.");

/*

*Since the container persists primary keys only, we must

*convert the loaded primary keys into EJB Objects.

*/ try {

/*

*Form JNDI initial context.

*Note: We rely on the environment properties

*that the bean was deployed with for any

*necessary initialization parameters.

*/

Context initCtx = new InitialContext(ctx.getEnvironment());

/*

* Lookup home objects via JNDI */

ProductHome productHome = (ProductHome) initCtx.lookup("Ecommerce.ProductHome");

OrderHome orderHome = (OrderHome) initCtx.lookup("Ecommerce.OrderHome");

/*

* Find the EJB Objects based upon their primary keys */

product = productHome.findByPrimaryKey(new ProductPK(productPK)); order = orderHome.findByPrimaryKey(new OrderPK(orderPK));

}

catch (Exception e) {

throw new RemoteException(e.toString());

}

}

/**

*Called when new database data is created.

*When the client calls the Home Object's

*create() method, the Home Object then calls

*this ejbCreate() method.

*

*We need to initialize our Bean's container-

*managed fields with the parameters passed

*from the client, so that the Container can

*inspect our Bean and create the corresponding

*database entries.

*/

Source 13.6 OrderLineItemBean.java (continues).

Go back to the first page for a quick link to buy this book online!