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

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

.pdf
Скачиваний:
45
Добавлен:
24.05.2014
Размер:
6 Мб
Скачать
☆

J2EE in the Real World: Implementing Our E-Commerce Session Beans 431

* customer name, discount */

StringTokenizer tokens = new StringTokenizer(discount, "=", false);

String discountCustomerName = tokens.nextToken(); percentDiscount =

Double.valueOf(tokens.nextToken()).doubleValue();

/*

*If this discount applies to this

*customer, then stop. Otherwise,

*move on to the next discount

*equation.

*/

if (!discountCustomerName.equals(customerName)) { continue;

}

System.out.println("Pricer.priceSubtotal(): " + customerName + " gets a " + percentDiscount + "% discount.");

}

}

catch (Exception e) {

System.out.println("Pricer.priceSubtotal(): " + customerName + " doesn't get a discount.");

}

/*

*Now we know how much discount to apply. The

*next step is to apply the discount to each

*product the customer is interested in.

*

*We need to get the price and quantity of each

*product the customer* wants. The quote object

*stores this information in individual quote

*line items. Each line item has price and

*quantity information for a single product.

*/

/*

*First, get the Line Items contained within the

*Quote.

*/

Enumeration lineItems = quote.getLineItems().elements();

/*

* Compute the subtotal */

Source 14.9 PricerBean.java (continues).

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

432 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

double subTotal = 0; try {

/*

* For each line item...

*/

while (lineItems.hasMoreElements()) {

QuoteLineItem li = (QuoteLineItem) lineItems.nextElement();

/*

* Get the price of the line item...

*/

double basePrice = li.getBasePrice();

/*

* Set the discount for this line item...

*/

li.setDiscount(basePrice * percentDiscount);

/*

* Apply the discount...

*/

double aggregatePrice =

basePrice - (basePrice * percentDiscount);

/*

* And add the price to the subtotal. */

subTotal += aggregatePrice;

}

quote.setSubtotal(subTotal);

}

catch (Exception e) {

throw new PricerException(e.toString());

}

}

/**

*Computes the taxes on a quote.

*Since the taxes are based on the subtotal, we assume

*that the subtotal has already been calculated.

*/

private void priceTaxes(Quote quote) throws PricerException, RemoteException { System.out.println("PricerBean.priceTaxes() called");

Properties props = ctx.getEnvironment();

Source 14.9 PricerBean.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 Session Beans 433

/*

* Compute the taxes */

String taxRateStr = (String) ctx.getEnvironment().get(ENV_TAX_RATE); double taxRate = Double.valueOf(taxRateStr).doubleValue();

double subTotal = quote.getSubtotal();

quote.setTaxes(taxRate * subTotal);

}

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

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

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

//Begin EJB-required methods. The methods below are

//called by the Container, and never called by client

//code.

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

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

}

public void ejbRemove() { System.out.println("ejbRemove() called.");

}

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

}

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

}

public void setSessionContext(SessionContext ctx) { System.out.println("setSessionContext() called"); this.ctx = ctx;

}

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

// End EJB-required methods //----------------------------------------------------

}

Source 14.9 PricerBean.java (continued).

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

434 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

PricerBean.priceSubtotal()

Our Pricer bean performs only one kind of discount—a customer-specific discount. These are discounts a preferred customer receives, such as a percentage discount on the entire Quote.

The correlation between discounts and customers is data-driven via the bean’s deployed environment properties. You can use the properties file to customize the bean’s pricing rules.

The customer-specific discount is computed in the following way:

1.Retrieve the customer’s name from the Customer object.

2.Read all the customer-specific discounts from the environment properties.

3.If a discount applies to this Customer, reduce the price based on that discount.

PricerBean.priceTaxes()

Once we’ve got the subtotal, we compute the tax on that subtotal. The tax rate is customizable and is also set in the bean’s deployed environment properties. We read the tax rate in and apply it to the subtotal, yielding the tax amount. This tax amount is set on the Quote.

Once we’ve set the taxes, the price() method is finished. We could easily add more steps as well, such as pricing the shipping.

PricerHome.java

Next, we’ll write our Pricer bean’s home interface. The home interface is used by clients as a factory for Pricer EJB objects. The code is in PricerHome.java, shown in Source 14.10.

The simple create() method makes a new Pricer EJB Object. As with all stateless session beans, there can be only one create() method, which takes no parameters.

PricerException.java

Our last Java class for our Pricer bean is a custom exception class, which is used by our bean when throwing bean-specific application-level exceptions. The code is in PricerException.java, shown in Source 14.11.

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

J2EE in the Real World: Implementing Our E-Commerce Session Beans 435

package com.wiley.compBooks.ecommerce;

import javax.ejb.*;

import java.rmi.RemoteException;

/**

*This is the home interface for Pricer. The

*container implements this interface; the

*implementation object is called the Home Object

*and serves as a factory for EJB Objects.

*/

public interface PricerHome extends EJBHome {

/*

*This method creates the EJB Object.

*@return The newly created EJB Object. */

Pricer create() throws RemoteException, CreateException;

}

Source 14.10 PricerHome.java.

package com.wiley.compBooks.ecommerce;

/**

* Exceptions thrown by Pricer */

public class PricerException extends Exception {

public PricerException() { super();

}

public PricerException(Exception e) { super(e.toString());

}

public PricerException(String s) { super(s);

}

}

Source 14.11 PricerException.java.

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

436 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

The Deployment Descriptor

Now that we’ve written our Pricer bean code, we need to declare properties about our bean in a deployment descriptor. The container will inspect the deployment descriptor and use its values to determine the proper ways to manage our bean. The deployment descriptor is shown in Table 14.3.

Because our Pricer is working with nonpersistent quote objects, and because the quote objects should not be shared between users, we can afford to use the simple TX_SUPPORTS attribute, which will attach our bean to an optional existing transaction in which the client may be running. We support the weakest isolation level as well—TRANSACTION_READ_UNCOMMITTED.

Our Pricer’s pricing rules are customizable by the environment properties. Some sample properties are listed in Table 14.4. Our customer-specific discounts are simple equations. For example, the setting “Ed Roman=50” indicates that Ed Roman should get a 50% discount.

The tax rate property is a simple float. Our example shows that all users pay a 5% tax on their orders.

By externalizing these rules into property files, we as bean providers can reuse this pricing bean for other customers. A more robust pricer might make use of

Table 14.3 Deployment Descriptor Settings for PricerBean

DEPLOYMENT

DESCRIPTOR SETTING

VALUE

Bean home name

Ecommerce.PricerHome

Enterprise bean class name

com.wiley.compBooks.ecommerce.PricerBean

Home interface class name

com.wiley.compBooks.ecommerce.PricerHome

Remote interface class name

com.wiley.compBooks.ecommerce.Pricer

Environment properties

<empty>

Re-entrant

false

Stateful or stateless

STATELESS_SESSION

Session timeout

15 minutes

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!

J2EE in the Real World: Implementing Our E-Commerce Session Beans 437

Table 14.4 Environment Properties for PricerBean

 

 

 

ENVIRONMENT PROPERTY SETTING

VALUE

 

 

DISCOUNT_1

“Ed Roman=50”

DISCOUNT_2

“James Kao=30”

DISCOUNT_3

“Jonah Probell=20”

TAX_RATE

“0.05”

 

 

a database as well, providing advanced pricing functionality and a user interface for manipulating pricing rules.

The Bank Teller Stateless Session Bean

Our final e-commerce bean is a Bank Teller, used for billing the customer after an Order has been generated. A teller represents a “virtual person” with whom you interact to modify a bank account. For example, our Teller will be able to transfer funds from one Bank Account (entity bean) to another.

Our Teller itself is not a persistent object—the notion of “saving” a Teller to disk means nothing. Our Tellers will be stateless method providers, and they will be reusable for multiple clients. Therefore, our Teller fits into the EJB world as a stateless session bean.

The Teller makes extensive interactions with the Bank Account bean described in Chapter 8. At this time, you may want to revisit that chapter to refresh your memory.

Billing Mechanisms

As EJB matures and bean providers become more abundant, you may see billing mechanisms similar to our Teller bean begin to surface. Most likely, they will be in the form of credit card beans that know how to interface with an American Express or VISA system elsewhere.

Because our structure is very modular, we could easily change our deployment to use a different billing system. For example, rather than store the user’s bank account information, we’d need to code the user’s credit card number in the Customer entity bean. That will allow us to save the user from having to reenter his or her credit card information each time he or she uses our site.

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

438 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

Teller.java

First, we’ll write our Teller’s remote interface—the interface client code uses to interact with our teller bean. The code is Teller.java, shown in Source 14.12.

Notice that almost every Teller method takes an account number as a parameter. This is because our Teller is stateless—it can operate on any existing bank account. We also have provided functionality to look up a bank account number if the user has lost it. Of course, in the real world a bank would impose some security restrictions, to verify the user’s identity.

package com.wiley.compBooks.ecommerce;

import javax.ejb.*;

import java.rmi.RemoteException; import java.rmi.Remote;

/**

*These are the business logic methods exposed publicly

*by TellerBean.

*

*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 Teller extends EJBObject {

/**

*Looks up an account number (if you forgot it)

*@param name Your full name

*/

public String lookupAccountNumber(String name) throws RemoteException, TellerException;

/**

*Creates a new account with a starting deposit.

*@param name Your full name

*@param initialDeposit The initial starting balance you

* want to deposit.

*

* @return Your new account number */

Source 14.12 Teller.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 Session Beans 439

public String createNewAccount(String yourName, double initialDeposit) throws RemoteException, TellerException;

/**

*Closes your account.

*@return The funds left in your account are returned to

*you.

*/

public double closeAccount(String accountNum) throws RemoteException, TellerException;

/**

*Gets your current balance for an account.

*@param accountNum the account number string.

*/

public double getBalance(String accountNum) throws RemoteException, TellerException;

/**

* Switches names on an account. */

public void changeNames(String accountNum, String newName) throws RemoteException, TellerException;

/**

* Transfers funds from accountNum1 to accountNum2 */

public void transfer(String accountNum1, String accountNum2, double funds) throws RemoteException, TellerException;

/**

*Withdraws from your account.

*@exception TellerException thrown if you have

*insufficient funds.

*@return Your withdrawn funds.

*/

public double withdraw(String accountNum, double funds) throws RemoteException, TellerException;

/**

* Deposits into your account. */

public void deposit(String accountNum, double funds) throws RemoteException, TellerException;

}

Source 14.12 Teller.java (continued).

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

440 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

TellerHome.java

Next, we’ll write our bank teller’s home interface, used by client code as a factory for bank teller EJB objects. The code is in TellerHome.java, shown in Source 14.13.

As with all stateless session beans, you cannot customize a bean with create() because the bean will not remember your state for the next invocation. Therefore we expose one create() method that takes no parameters and returns a new EJB Object.

TellerBean.java

Next, we’ll write our teller bean’s implementation. The code is in TellerBean.java, shown in Source 14.14.

Our Teller bean has a number of interesting facets. For one, we need to store a private home object for creating and finding Bank Account entity beans for us

package com.wiley.compBooks.ecommerce;

import javax.ejb.*;

import java.rmi.RemoteException;

/**

*This is the home interface for TellerBean. This

*interface is implemented by the EJB Server's glue-

*code tools - the implemented object is called the

*Home Object and serves as a factory for EJB Objects.

*One create() method is in this Home Interface, which

*corresponds to the ejbCreate() method in the

*TellerBean file.

*/

public interface TellerHome extends EJBHome {

/*

*This method creates the EJB Object.

*@return The newly created EJB Object. */

Teller create() throws RemoteException, CreateException;

}

Source 14.13 TellerHome.java.

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