BEA Logo BEA WebLogic Enterprise Release 5.1

  Corporate Info  |  News  |  Solutions  |  Products  |  Partners  |  Services  |  Events  |  Download  |  How To Buy

 

   WebLogic Enterprise Doc Home   |   Getting Started & Related Topics   |   Previous Topic   |   Next Topic   |   Contents   |   Index

Designing Enterprise JavaBeans for the WebLogic Enterprise System

 

This topic includes the following sections:

The information in this chapter supplements the Sun Microsystems, Inc. Enterprise JavaBeans Specification 1.1.

 


Designing EJB Applications for the WebLogic Enterprise System

The WebLogic Enterprise software complies with the EJB Specification 1.1. However, to design EJB applications that take advantage of the WebLogic Enterprise architecture, you need to follow certain design rules and patterns. This section describes these design considerations with respect to the following perspectives on the WebLogic Enterprise EJB environment:

The Client Application Programmer's View

Client application programmers using EJBs have a uniform development model they can use for beans regardless of whether the beans are local or remote. For each EJB, client programmers have access to the information in Table 8-1.

Table 8-1 EJB Information that Client Programmers Can Access

Information

Description

The bean's home interface

Each EJB has a home interface (factory) that creates instances of the bean. The home interface defines the methods used by client programmers to create, remove, and find objects of the corresponding EJB type. To find a reference to a particular bean home interface, client applications should use the lookup method of the InitialContext object with the PortableRemoteObject class. In the WebLogic Enterprise system, home interfaces are available, and can be advertised, across domains.

The bean's remote interface

Each EJB has a well-defined remote interface that defines the business methods that can be invoked by a client.

The object identity

Each EJB instance lives in a home and has a unique identity within its home. The identity of a session bean is generated by the EJB container and is not exposed to the client. The Bean Provider generates the identity of an entity bean (the primary key) and a client can retrieve the primary key from the entity object reference.

The bean's metadata interface

The metadata interface allows clients (typically, application assembly tools) to discover the metadata information about the bean.

The object handle

The handle identifies the object in a portable way. The handle can be serialized. Having a serialized handle lets you store the handle and then use it at a later time, possibly in a different process or in a different system, or by another bean or object. Handles are more useful with entity beans than with session beans.

To access any EJB, a client application needs to obtain a reference from the bean's home interface (factory); however, because the home is also an object, the client needs also to obtain a reference to it. Getting a home reference to the client application presents a bootstrapping problem. However, when you register home references with a directory service -- namely, JNDI -- client applications have a means to obtain a reference to the bean's home, even across WebLogic Enterprise domains. This is exactly what the WebLogic Enterprise EJB container provides.

From the WebLogic Enterprise EJB container perspective, client applications (including JSP and servlets acting as clients) are nontrusted entities that require authentication. They typically require a network connection to access the WebLogic Enterprise EJB container because they run on nontrusted machines.

How to set up this network connection is another bootstrapping problem. This is solved in WebLogic Enterprise by providing a JNDI implementation that runs within the EJB container trusted environment, and by establishing the network connection when the JNDI initial context is created. The parameters required for the initialization are Java properties (name/value pairs) passed as arguments to the constructor of the InitialContext object.

A WebLogic Enterprise client application can set the properties shown in Table 8-2.

Table 8-2 InitialContext Object Parameters

Property Name

Values

Description

WLEContext.
INITIAL_CONTEXT_FACTORY

com.beasys.jndi.
WLEInitialContextFactory

Specifies the WebLogic Enterprise JNDI.

WLEContext.PROVIDER_URL

corbaloc://<host:port> or corbalocs://<host:port>

Defines the address of the entry points to the WebLogic Enterprise environment. The identifier corbaloc indicates that the protocol is WebLogic RMI on IIOP. The identifier corbalocs indicates that the protocol is WebLogic RMI on IIOP with SSL.

WLEContext.
SECURITY_AUTHENTICATION

none | simple | strong

Defines the type of authentication:

  • none means no authentication (this is the default).

  • simple means WebLogic Enterprise authentication.

  • strong means SSL authentication (certificate-based).

WLEContext.
SECURITY_PRINCIPAL

<Principal Identifier>

Specifies the security principal name. For more information, see Using Security in the WebLogic Enterprise online documentation.

WLEContext.
SECURITY_CREDENTIALS

<SSL credentials> or
<User Password>

Specifies the credentials when authentication is strong, or the user password when authentication is simple.

WLEContext.CLIENT_NAME

<Security role>

Specifies the security role name used by simple authentication. For more information, see Using Security in the WebLogic Enterprise online documentation.

WLEContext.
SYSTEM_PASSWORD

<password>

Specifies the system password if the simple authentication is in effect.

WLEContext.CODEBASE

<url>

Specifies the URL for remote class loading.

The client application is implicitly associated with the security context specified when the InitialContext object is created. To specify a new security context -- for example, to invoke objects in a different WebLogic Enterprise domain -- the client application needs to close the current context and establish a new context with the new security attributes. To find a reference to a particular bean home interface, client applications should use the lookup method of the InitialContext object with the PortableRemoteObject class. Client applications can also use the lookup method to obtain a reference to the UserTransaction object. WebLogic Enterprise client applications cannot modify the WebLogic Enterprise JNDI naming context; that is, client applications can perform only lookup operations on this context.

The client can use the bean home interface to find or create session or entity bean instances. The create method provided by the EJB home interface creates the requested EJB and returns a reference to it. The client uses the reference for as long as it needs, and when it finishes, can invalidate the reference (and eventually the EJB instance) by invoking the ejbRemove method on the EJB instance. Between these method invocations, the client can invoke (optionally within a transaction) any of the business methods provided by the EJB.

The WebLogic Enterprise system complies with the EJB Specification 1.1, and client programmers must be aware of the subtle programming differences provided by the different bean types (refer to the EJB Specification for more details).

Also note that the WebLogic RMI on IIOP protocol is not currently supported for applets running on a Web browser.

The EJB Programmer's View

As an EJB programmer, or Bean Provider, as identified in the EJB Specification, you must follow the conventions and programming restrictions established in the EJB Specification 1.1 for the different EJB types. The following are the principal design considerations to take into account when implementing beans with the WebLogic Enterprise EJB environment:

The sections that follow discuss each of these considerations in detail.

Choosing Between Session and Entity Beans

When to use one bean type or another depends upon the design pattern that bean programmers want to use. There are a few commonly used rules:

Server Startup

The WebLogic Enterprise EJB container gives you the flexibility to specify an object that is invoked by the EJB container when a WebLogic Enterprise server process loads an EJB JAR file. This object is an instance of a class that implements the Server interface, and is thus referred to as a module initializer object. Implementing the module initializer object is described in the section Step 2: Create the Module Initializer Object.

You can use the module initializer object to perform specialized initialization for some objects, such as instantiating RMI objects. In WebLogic Enterprise EJB applications, you can specify this class in the <module-initializer-class> element in the WebLogic EJB extensions to the deployment descriptor DTD, which is a special deployment descriptor that you create along with the standard deployment descriptor.

Home Interface Registration

When an EJB JAR file is deployed, the WebLogic Enterprise container recognizes the EJB home interfaces (factories) and automatically registers them within the WebLogic Enterprise JNDI context. The information about the home interfaces is retrieved from the deployment descriptor.

Bean Activation and Passivation

EJB containers have complete control of the passivation of EJBs. This allows the container to pool instances of a bean and to decide when an instance can be passivated (or removed from the pool) to provide better use of system resources.

As a bean programmer, you cannot make any assumptions about when a bean object is passivated. This passivation can happen at any time. This is particularly important when the bean accesses a database via cursors, because these cursors could become invalid after the passivation; the EJB container can reactivate the bean in another server process.

The WebLogic Enterprise EJB container currently follows a passivation model that is similar to the model used by the WebLogic Enterprise TP Framework for CORBA applications. If resources are scarce, the WebLogic Enterprise EJB container may passivate an object at any time. When the bean is reactivated, it may be reactivated in the same server process or in another server process in the same group.

If a client application creates or invokes a stateful or entity bean within a transaction, the bean will never be passivated while it is participating in the transaction. If the client invocation is nontransactional, the bean may be passivated at the end of the method invocation.

For concurrency control, the WebLogic Enterprise system applies the following rules:

Controlling the Passivation of Beans -- the EJB Cache

In WebLogic Enterprise 5.0, the EJB container cached stateful beans only for the duration of a transaction. If such beans were not involved in a transaction, the container passivated them after each method invocation on the bean.

In versions of WebLogic Enterprise after 5.0, the EJB container has the ability to cache beans across method invocations as well as across transactions. This significantly reduces the frequency of beans being passivated, thereby providing the performance improvement. EJB caching is enabled by default for stateful beans.

When Stateful Beans Are Passivated

A cached stateful bean is normally only stored (passivated) if it is unused for a period of time. You can configure an optional cache flush time, if desired. A bean may be considered unused if other beans are being used more frequently and the bean is the least recently used bean. The bean may also be passivated if the cache flush time occurs and the bean is not presently active within a method call or a transaction.

Passivation After Creation

In the WebLogic Enterprise system, the EJB container still passivates stateful beans immediately after the ejbCreate method is called. This behavior may change in future releases, however.

How to Set Up EJB Caching

EJB caching is enabled by default for stateful session beans and entity beans in the EJB container of theWebLogic Enterprise system, and can be set up using the following mechanisms:

For more information about setting up the bean cache, see the section "Starting JavaServer" in the topic Creating a Configuration File. For information about scaling and tuning the bean cache, see Scaling, Distributing, and Tuning Applications.

EJBs as Client Applications

A bean may invoke the methods of another bean. When a bean behaves as a client application, the client rules still apply: the bean must obtain the reference to the other bean from that bean's home interface (factory), and references to the home interface must be obtained using JNDI.

The main differences with the client environment are the following:

Security, Transactions, and JDBC Connections

For additional EJB design considerations, see the following in the WebLogic Enterprise online documentation:

 


EJBs and Persistence

This section provides a general discussion about EJBs and persistence, and shows sample fragments of EJB implementation code and deployment descriptors to illustrate the following:

The topics described in this section use code from the EJB sample applications that are installed with the WebLogic Enterprise software.

Note: The code fragments shown in this section are taken from the EJB samples provided with the WebLogic Enterprise software. These samples include tracing code, which is turned on by the VERBOSE flag, that helps show what is happening when the samples are executed. These tracing statements are not required by the EJB Specification 1.1; they are present for instructional purposes only.

Development Considerations for EJBs and Persistence

Persistence refers to a bean's state information, which may be contained in durable storage when the bean is not active. When the bean is activated, this state is read in from durable storage. As a Bean Provider, you basically have two choices for what kind of broad mechanism you want to use for handling a bean's persistence: either directly in the bean's logic, or by delegating to the EJB container the tasks of handling the bean's persistence.

A bean that delegates to the container all the logic for handling its persistent data has what is referred to as container-managed persistence. A bean that contains its own logic for handling its persistence data has what is referred to as bean-managed persistence. The choice you make for a bean must be specified in the bean's deployment descriptor.

Container-managed Entity Beans

If your entity bean uses container-managed persistence, you need to do the following:

The subsections that follow also provide code fragments that show the use of the ejbCreate, ejbStore, and ejbRemove methods in such beans.

Required Deployment Descriptor Elements for Container-managed Beans

The required deployment descriptor elements for container-managed beans are listed and described in Table 8-3.

Table 8-3 Required Deployment Descriptor Elements for Container-managed Beans

Deployment Descriptor Element

Description

cmp-fields

This element specifies the container-managed fields. This is a standard property that lists the public nontransient instance variables that the EJB expects will be made automatically persistent. Even if there are no managed fields, the bean's object reference and the primary key are remembered by the EJB container.

persistence-type

If the EJB is an entity bean, this element declares whether the persistence management is performed by the container or by the bean. For container-managed persistence, this element should specify container.

persistence-store-jdbc

This element specifies that the type of persistent store is jdbc. (Note that in WebLogic Enterprise, file-based persistence for entity beans is not supported.)

primary-key-class

The deployment descriptor for any entity bean must set this element, which identifies the primary key class for the bean.

Declaring Container-managed Fields as Public Variables

The following code fragment shows a container-managed EJB declaring its container-managed fields as public class variables. These variables need to be public so that the container can manage them.

  // public container managed variables
public String accountId; // also the primary Key
public double balance;
public String type; // "Checking"

The ejbCreate Method

A container-managed entity bean needs to implement the ejbCreate method. Note that the accountId and initialBalance parameters in this method are managed by the container. The following code fragment shows a container-managed bean setting the values of the public class variables shown in the code fragment in the section Declaring Container-managed Fields as Public Variables.

public void ejbCreate(String accountId, double initialBalance,
String type) {
if (VERBOSE)
System.out.println("ejbCreate( id = " + id() +
", initial balance = $" + initialBalance +
", type: " + type + ")");
this.accountId = accountId;
this.balance = initialBalance;
this.type = type;
}

The ejbStore Method

The EJB Specification 1.1 states that implementing the ejbStore method in a container-managed entity bean is required, even if the method does not provide any specific functionality. One advantage to having this method in your container-managed bean is to provide a tracing capability for debugging purposes, as in the following example:

public void ejbStore() {
if (VERBOSE)
System.out.println("ejbStore (" + id() + ")");
}

The ejbRemove Method

As with the ejbStore method in the preceding section, the ejbRemove method is not a functional component of a container-managed bean implementation; however, the EJB Specification 1.1 requires this method to be present, as in the following example:

public void ejbRemove() throws RemoveException {
if (VERBOSE)
System.out.println("ejbRemove (" + id() + ")");
}

Bean-managed Entity Beans

If you are implementing a bean with bean-managed persistence, you need to do the following:

The code fragments provided in this section illustrate performing these tasks, as well as using the ejbRemove method to remove a bean's persistent data from a database.

Accessing the JDBC Pool

The following code example shows a bean-managed entity bean using static initialization to establish access to the JDBC pool, which is defined in the EJB application's UBBCONFIG file:

static {
try{
Context ctx = new InitialContext();
pool = (DataSource)ctx.lookup("jdbc/pool1");
} catch(Exception e) {
System.out.println("problem with datasource.");
}
}

The ejbCreate Method

A bean-managed entity bean uses the ejbCreate method to create the bean and update the table in the database that contains the entity bean's value. Listing 8-1 shows creating a row in the table in that database, using a JBDC connection from the pool.

Listing 8-1 Entity Bean Creating a Row in a Database


public AccountPK ejbCreate(String account_id, double initial_balance)
throws CreateException,
{
if (VERBOSE) {
System.out.println("AccountBean.ejbCreate( id = " +
System.identityHashCode(this) + ", PK = " +
account_id + ", " + "initial balance = $ " +
initial_balance + ")");
}
AccountId = account_id;
Balance = initial_balance;

Connection connection = null;
PreparedStatement prep_stmt = null;


try {
connection = pool.getConnection();
prep_stmt = connection.prepareStatement("insert into ejbAccounts "+
"(id, bal) values (?, ?)");
prep_stmt.setString(1, AccountId);
prep_stmt.setDouble(2, Balance);
if (prep_stmt.executeUpdate() != 1) {
throw new CreateException ("JDBC did not create any row");
}
AccountPK primary_key = new AccountPK();
primary_key.AccountId = AccountId;
return primary_key;
} catch (CreateException ce) {
throw ce;
} catch (SQLException sqe) {
throw new CreateException (sqe.getMessage());
} finally {
try {
prep_stmt.close();
connection.close();
} catch (Exception e) {
}
} // end of finally
} // end of ejbCreate(..)

Updating the Database

The following code fragment shows updating the database with the values. Since this bean uses bean-managed persistence, updating the database is done manually. Whereas the code in the previous example created the database rows, the code in Listing 8-2 specifies the values in those rows.

Listing 8-2 Entity Bean Updating the Database


ejbStore()
public void ejbStore() throws EJBException {

if (VERBOSE) {
System.out.println("ejbStore (" + id() + ")");
}
Connection connection = null;
PreparedStatement prep_stmt = null;
try {
connection = pool.getConnection();
prep_stmt = connection.prepareStatement("update ejbAccounts set bal = "+
"? where id = ?");
prep_stmt.setDouble(1, Balance);
prep_stmt.setString(2, AccountId);
int i = prep_stmt.executeUpdate();
if (i == 0) {
throw new RemoteException ("ejbStore: AccountBean (" + AccountId +
") not updated");
}
} catch (RemoteException re) {
throw re;
} catch (SQLException sqe) {
throw new EJBException (sqe.getMessage());
} finally {
try {
prep_stmt.close();
connection.close();
} catch (Exception e) {
throw new EJBException (e.getMessage());
}
} // end of finally
} // end of ejbStore()

Removing Values From the Database

Listing 8-3 shows using the ejbRemove method to remove rows from the database that were created and set in the preceding code examples.

Listing 8-3 Removing Values From a Database


public void ejbRemove()
throws RemoveException,
{
if (VERBOSE) {
System.out.println("ejbRemove (" + id() + ")");
}
// we need to get the primary key from the context because
// it is possible to do a remove right after a find, and
// ejbLoad may not have been called.

Connection connection = null;
PreparedStatement prep_stmt = null;
try {
connection = getConnection();
AccountPK pk = (AccountPK) ctx.getPrimaryKey();
prep_stmt = connection.prepareStatement("delete from ejbAccounts where "+
"id = ?");
prep_stmt.setString(1, pk.AccountId);
int i = prep_stmt.executeUpdate();
if (i == 0) {
throw new EJBException ("AccountBean ("
+ pk.AccountId + " not found");
}
} catch (RemoteException re) {
throw re;
} catch (SQLException sqe) {
throw new RemoteException (sqe.getMessage());
} finally {
try {
prep_stmt.close();
connection.close();
} catch (Exception e) {
throw new EJBException (e.getMessage());
}
} // end of finally
} // end of ejbRemove()

Stateful Session Beans

This section shows the following examples of stateful session beans:

The code examples shown here are from the EJB Samples directory, which is available with the WebLogic Enterprise software.

Example Deployment Descriptor

A deployment descriptor for a stateful session bean can optionally define the persistentDirectoryRoot element. The default file is /pstore/bean_name.dat, where the directory pstore represents the directory from which the WebLogic Enterprise application was started, and bean_name is the fully qualified name of the EJB with underscores (_) replacing the periods (.) in the name.

If the persistentStoreType element is defined as jdbc, the container looks for additional values to determine the appropriate values for the JDBC connection. Note that if the bean's persistence is stored in a database via a JDBC connection, the System Administrator needs to add this information to the UBBCONFIG file as well. For more information, see Using the JDBC Drivers in the WebLogic Enterprise online documentation.

The following deployment descriptor fragment shows the location of the persistent store for a stateful session bean:

<persistence-store-descriptor>
<persistence-store-file>
<persistence-store-directory-root>
c:\mystore
</persistence-store-directory-root>
</persistence-store-file>
</persistence-store-descriptor>

Client Application Maintaining a Bean's State Information

The following code example shows an EJB client application keeping track of a bean's state information. In stateful session beans, you need to provide a one-to-one mapping between the client and the bean in the server, represented by a key. This key provides the map between the bean's instance and the client, because the bean instance cannot be shared with other clients.

Listing 8-4 shows the client application code creating the stateful session bean using the primary class key.

Listing 8-4 Client Application Using the Primary Class Key


// Give this trader a name
Trader trader = brokerage.create("Terry");
System.out.println("Creating trader " + trader.getTraderName() + "\n");

String stockName;
int numberOfShares;

for (int i = 1 ; i <= 5; i++) {
System.out.println("Start of Transaction " + i + " for " + customerName);

// Buying
stockName = "WEBL";
numberOfShares = 100 * i;
System.out.println("Buying " + numberOfShares + " of " + stockName);
TradeResult tr = trader.buy(customerName, stockName, numberOfShares);
System.out.println("...Bought " + tr.numberTraded + " at $" +
tr.priceSoldAt);
// Selling
stockName = "INTL";
numberOfShares = 100 * (i+1);
System.out.println("Selling " + numberOfShares + " of " + stockName);
tr = trader.sell(customerName, stockName, numberOfShares);
System.out.println("...Sold " + tr.numberTraded + " at $" +
tr.priceSoldAt);

// Get change in Cash Account from EJBean
System.out.println("Change in Cash Account: $" + trader.getBalance());

System.out.println("End of Transaction " + i + "\n");
}
System.out.println("Change in Cash Account: $" + trader.getBalance() + "\n");
System.out.println("Removing trader " + trader.getTraderName());
trader.remove();
}
catch (ProcessingErrorException pe) {
System.out.println("Processing Error: " + pe);
pe.printStackTrace();
}
catch (Exception e) {
System.out.println(":::::::::::::: Error :::::::::::::::::");
e.printStackTrace();
}

Bean Keeping Track of Its Own State

Listing 8-5 shows a stateful session bean keeping track of its state, and its mapping to a specific client. For example, the balance is kept on the EJB rather than on the client.

Listing 8-5 EJB State Management


  // The reason the following attribute is public is to test 
// passivation into a persistent store, because the deployment descriptor
// says it should be a stateful session bean.
// This and the ejbCreate method in this file are the differences
// between the examples in the stateful and stateless directories.
public String traderName;
public double tradingBalance;

// -----------------------------------------------------------------
.
.
.

public TradeResult buy(String customerName, String stockSymbol,
int shares)
throws ProcessingErrorException
{
if (VERBOSE && shares >= 0) {
System.out.println("buy (" + customerName + ", " +
stockSymbol + ", " +
shares + ")");
}
try {
int tradeLimit = getTradeLimit();
if (shares > tradeLimit) // limit for buying
shares = tradeLimit;
else if (shares < -tradeLimit) // limit for selling
shares = -tradeLimit;

double price = getStockPrice(stockSymbol);
tradingBalance = tradingBalance - (shares * price); // subtract purchases from cash account

if (shares < 0)
shares = -shares;
return new TradeResult(shares, price);
}
catch (Exception e) {
throw new ProcessingErrorException("Trader error: " + e);
}
}

Stateless Session Beans

This section provides the following two code examples:

Client Maintaining Bean's State

Listing 8-6 shows a client application keeping track of the cashBalance variable, which is manipulated by the stateless bean. This example also shows the client invoking the ejbCreate method without any arguments and without any specific data.

Listing 8-6 Client State Management


 try {
String customerName = "Erin"; // Default name for the customer
Context ctx = null; // To hold JNDI context
Object objref = null; // to hold object reference

String stockName = null; // Name of a stock
int numberOfShares = 0; // No. of shares to trade
double cashBalance = 0.0; // To hold balance between sessions

TraderHome brokerage = null; // To hold home interface
Trader trader = null; // To hold trader object
TradeResult tradeResult = null; // To hold results from a trade

// Create a new initial context based on the url, user, and password
ctx = newInitialContext();

if ( ctx == null ){
System.out.println("Initial context is null");
exit(-1);
}
// do a JNDI lookup for the EJB;defined in the deployment descriptor
objref = ctx.lookup("statelessSession.TraderHome");
printTrace("Looked up home:");

/* Create a trader object, who'll later help us execute trades
* The lookup has resulted in an Object. We know
* this object is actually a reference of type TraderHome,
* so the reference is narrowed and cast to that type:
*/
brokerage = (TraderHome) PortableRemoteObject.narrow(objref,
TraderHome.class);
printTrace("Narrowed home.");

/* Create the EJB on the WLE server.
* Unlike the statefulSession example,we don't give this trader a key
*/
printTrace("Creating trader.");
trader = brokerage.create();

/* Unlike the statefulSession example,
* we have to keep track of the balance over the
* life of our use of the session bean
*/

for (int i = 1 ; i <= maxTransaction; i++) {
System.out.println("Start of Transaction " + i + " for " +
customerName);

/* Buying
* Stock symbol must be found in the deployment descriptor's environment
* properties section. TraderBean EJB will check the validity of the
* symbol, and its price using JNDI lookup on the environment
* properties.
*/

stockName = "BEAS";
numberOfShares = 100 * i;
System.out.println("Buying " + numberOfShares + " of " + stockName);

// buy() is executed on the TraderBean EJB in the WLE Server
tradeResult = trader.buy(customerName, stockName, numberOfShares);
System.out.println("...Bought " + tradeResult.numberTraded + " at $" +
tradeResult.priceSoldAt);

// Keep track of the change in the Cash Account
cashBalance = cashBalance - (tradeResult.numberTraded *
tradeResult.priceSoldAt);

// Selling
stockName = "INTL";
numberOfShares = 100 * (i+1);
System.out.println("Selling " + numberOfShares + " of " + stockName);

// sell() is executed on the TraderBean EJB in the WLE Server
tradeResult = trader.sell(customerName, stockName, numberOfShares);
System.out.println("...Sold " + tradeResult.numberTraded + " at $" +
tradeResult.priceSoldAt);

// Keep track of the change in the Cash Account
cashBalance = cashBalance + (tradeResult.numberTraded *
tradeResult.priceSoldAt);

// Print change in Cash Account
System.out.println("Change in Cash Account: $" + cashBalance);
System.out.println(

Stateless Bean Tracking Its Own State

Listing 8-7 shows a business method from the TraderBean example, available in the EJB Samples directory provided with the WebLogic Enterprise software. In this example, the bean does not preserve any state. The bean's buy method performs simple calculations on data provided by the client application.

Listing 8-7 Stateless Bean State Management


getStockPrice() and getTradeLimit() methods use DD environment properties to access constant values using JNDI lookup() - prevents hardcoding data.

public TradeResult buy(String customerName, String stockSymbol,
int shares)
throws ProcessingErrorException
{

if (shares >= 0) {
printTrace("buy (" + customerName + ", " +
stockSymbol + ", " +
shares + ")");
}
try {
int tradeLimit = getTradeLimit();
if (shares > tradeLimit)
shares = tradeLimit;
else if (shares < -tradeLimit) // limit for selling
shares = -tradeLimit;

double price = getStockPrice(stockSymbol);
printTrace("Executing buy...");
if (shares < 0)
shares = -shares;
return new TradeResult(shares, price);
}
catch (Exception e) {
throw new ProcessingErrorException("Trader error: " + e);
}
}