|
|
This topic includes the following sections:
The information in this chapter supplements the Sun Microsystems, Inc. evolving Enterprise JavaBeans 1.1 Specification (Public Release 2, October 18, 1999).
The WLE software complies with the EJB 1.1 Specification. However, to design EJB applications that take advantage of the WLE architecture, you need to follow certain design rules and patterns. This section describes these design considerations with respect to the following perspectives on the WLE EJB environment:
Designing EJB Applications for the WLE System
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 following:
The Client Application Programmer's View
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. This is exactly what the WLE EJB container provides.
From the WLE 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 WLE EJB container because they run on nontrusted machines.
How to set up this network connection is another bootstrapping problem. This is solved in WLE 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 WLE client application can set the following properties:
Property Name |
Values |
Description |
---|---|---|
Specifies the system password if the simple
authentication is in effect.
|
||
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 WLE 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. WLE client applications cannot modify the WLE 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 WLE system complies with the EJB 1.1 Specification, 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.
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 1.1 Specification for the different EJB types. The following are the principal design considerations to take into account when implementing beans with the WLE EJB environment:
The EJB Programmer's View
The sections that follow discuss each of these considerations in detail.
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:
Choosing Between Session and Entity Beans
When developing a stateful session bean, you must implement the ejbPassivate and ejbActivate methods in such a way that resources like JDBC connections and network connections are handled properly. While the EJB container is responsible for saving the conversational state in a portable way and for reconstructing that state during activation, some precautions must be taken by the Bean Provider to ensure that the EJB container handles state correctly. (See section 6.4.1 in the EJB 1.1 Specification for more information.) You can also decide if the bean's state needs to be synchronized when the bean is involved in a distributed transaction.
Entity beans can be used in many ways; for example, to implement a persistent variant of CORBA objects or to provide an object representation of entities stored in a database. You must be careful when you use entity beans to model objects stored in a database, because these beans could introduce inefficiencies, such as having most of the business logic on the client application rather than in the server application. Moving the business logic to the server application reduces the number of invocations needed to perform a particular business transaction.
The WLE EJB container gives you the flexibility to specify an object that is invoked by the EJB container when a WLE 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 6: Specify the module initializer object in the WebLogic EJB extensions to the deployment descriptor DTD..
You can use the module initializer object to perform specialized initialization for some objects, such as instantiating RMI objects. In WLE 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.
When an EJB JAR file is deployed, the WLE container recognizes the EJB home interfaces (factories) and automatically registers them within the WLE JNDI context. The information about the home interfaces is retrieved from the deployment descriptor.
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 WLE EJB container currently follows a passivation model that is similar to the model used by the WLE TP Framework for CORBA applications. If resources are scarce, the WLE 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 WLE system applies the following rules:
Server Startup
Home Interface Registration
Bean Activation and Passivation
Note: If a passivated stateful bean is not removed due to application or system errors, its passivated state takes up disk space in the location specified by the <persistence-store-directory-root> element. This passivated state remains on disk until the temporary files containing that state are deleted by the System Administrator. These files can be identified by the syntax of their names, which include the following information:
The server name and bean name components of the file name are the most readily identifiable. To manage the number of unused bean state files that can potentially accumulate over time, System Administrators may choose to create scripts that delete those files whenever the WLE system is started or shut down.
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:
EJBs As Client Applications
Note: The WLE EJB container does not propagate the security and transaction context on callbacks to a J2EE client.
For additional EJB design considerations, see the following in the WebLogic Enterprise online documentation:
Security, Transactions, and JDBC Connections
This topics provides the following sections:
Developing EJB Applications for the WLE System
The primary steps for developing an EJB are the following:
Development Steps
After you have created the EJB JAR file, you can then build and deploy the bean. The process for deploying an EJB in the WLE environment is described in Building and Deploying Enterprise JavaBeans (EJBs).
The EJB 1.1 Specification, published by Sun Microsystems, Inc., describes the different requirements of the EJB writer and the EJB framework; EJBs created for the WLE environment must conform to those requirements. When you write EJBs, pay close attention to these requirements.
When writing an EJB, you must implement the following:
Step 1: Write or obtain an EJB.
Note that the direct use of threads by Bean Providers is discouraged by the EJB 1.1 Specification. This constraint also applies to WLE server applications -- bean and RMI implementers should not attempt to manage, change properties, start, stop, suspend, or resume a thread or a thread group.
The ejbc
command, which is provided with the WLE development software, includes a compliance checker utility that examines the packaged EJBs and determines if the EJBs conform to these requirements.
For examples of bean implementations, see the section EJB Examples.
The deployment descriptor ties together the different classes and interfaces, and is used by the ejbc
command to build the code-generated class files. You can also use the deployment descriptor to specify critical aspects of the EJB's deployment at run time.
The elements that you, as the Bean Provider, need to specify in the deployment descriptor for each EJB is listed and described in the following table.
Step 2: Create a deployment descriptor.
Required Elements in the Deployment Descriptor
For complete details about the elements you specify in the standard deployment descriptor, see the EJB XML Reference in the WebLogic Enterprise online documentation.
You can create the deployment descriptor by any of the following methods:
How to Create the Deployment Descriptor
The DDGenerator
command is available from the WLE Developer Center. For information about locating and using this tool, see the Release Notes.
The deployment descriptor you create must:
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise
JavaBeans 1.1//EN" "http://java.sun.com/j2ee/dtds/ejb-jar_1_1.dtd">
The following is an example standard deployment descriptor for a container-managed entity bean. The specific class variables whose persistence is container-managed are accountId
and salary
. These fields are declared public in the bean's implementation, and are shown in boldface type in the following example:
<ejb-jar> In this step, you package the deployment descriptor, the source files for the EJB classes, and any additional required classes into a special kind of JAR file called the EJB JAR file. You can package multiple beans together, provided that there is a deployment descriptor for each bean.
You can use the WLE ejbc
command to create the EJB JAR file, as in the following example:
java weblogic.ejbc -i ejb-jar.xml -x weblogic-ejb-extensions.xml ejb-jar-file In the preceding command line, the -i
option specifies the name of the deployment descriptor, and ejb-jar-file
represents the name of the EJB JAR file. For more information about the ejbc
command, see Command Reference in the WebLogic Enterprise online documentation. Note that using the -validate
option is recommended.
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:
<enterprise-beans>
<entity>
<ejb-name>
oracle
</ejb-name>
<home>
samples.j2ee.ejb.sequence.oracle.OracleHome
</home>
<remote>
samples.j2ee.ejb.sequence.oracle.Oracle
</remote>
<ejb-class>
samples.j2ee.ejb.sequence.oracle.OracleBean
</ejb-class>
<!-- Primary key class -->
<persistence-type>
Container
</persistence-type>
<prim-key-class>
samples.j2ee.ejb.sequence.oracle.OraclePK
</prim-key-class>
<!-- Specify type of persistence -->
<reentrant>
false
</reentrant>
<!-- Container managed fields for this EJB -->
<cmp-field>
<field-name>
accountId
</field-name>
</cmp-field>
<cmp-field>
<field-name>
salary
</field-name>
</cmp-field>
<!-- Environment entries: Application specific and referred by
OracleBeanBean
-->
<env-entry>
<env-entry-name>
sequenceName
</env-entry-name>
<env-entry-type>
java.lang.String
</env-entry-type>
<env-entry-value>
ejbSequence
</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>
creationRange
</env-entry-name>
<env-entry-type>
java.lang.Integer
</env-entry-type>
<env-entry-value>
4
</env-entry-value>
</env-entry>
<!-- VERBOSE is used to set tracing on or off in EJBean-->
<env-entry>
<env-entry-name>
VERBOSE
</env-entry-name>
<env-entry-type>
java.lang.Boolean
</env-entry-type>
<env-entry-value>
true
</env-entry-value>
</env-entry>
</entity>
</enterprise-beans>
<!-- Assembly information -->
<assembly-descriptor>
<container-transaction>
<method>
<ejb-name>
oracle
</ejb-name>
<method-name>
*
</method-name>
</method>
<trans-attribute>
Required
</trans-attribute>
</container-transaction>
</assembly-descriptor>
</ejb-jar> Step 3. Package the EJB components into a Java Archive (JAR) file.
EJB Examples
The topics described in this section use code from the EJB sample applications that are installed with the WLE software.
Note:
The code fragments shown in this section are taken from the EJB samples provided with the WLE 5.0 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 1.1 Specification; they are present for instructional purposes only.
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.
If your entity bean uses container-managed persistence, you need to do the following:
Development Considerations for EJBs and Persistence
Container-managed Entity Beans
Note: The EJB 1.1 Specification requires that class variables whose persistence is container-managed have public access.
The subsections that follow also provide code fragments that show the use of the ejbCreate
, ejbStore
, and ejbRemove
methods in such beans.
The required deployment descriptor elements for container-managed beans are listed and described in the following table.
Required Deployment Descriptor Elements for Container-managed Beans
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, and they are also specified in the sample deployment descriptor shown in the section How to Create the Deployment Descriptor.
// public container managed variables 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, The EJB 1.1 Specification 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() { 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 1.1 Specification requires this method to be present, as in the following example:
public void ejbRemove() throws RemoveException { If you are implementing a bean with bean-managed persistence, you need to do the following:
Declaring Container-managed Fields as Public Variables
public String accountId; // also the primary Key
public double balance;
public String type; // "Checking" The ejbCreate Method
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
if (VERBOSE)
System.out.println("ejbStore (" + id() + ")");
} The ejbRemove Method
if (VERBOSE)
System.out.println("ejbRemove (" + id() + ")");
} Bean-managed Entity Beans
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.
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 { 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. The following code fragment shows creating a row in the table in that database, using a JBDC connection from the pool:
public AccountPK ejbCreate(String account_id, double initial_balance) 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 the following fragment specifies the values in those rows.
ejbStore() The following code fragment shows using the ejbRemove
method to remove rows from the database that were created and set in the preceding code examples.
public void ejbRemove() This section shows the following examples of stateful session beans:
Accessing the JDBC Pool
try{
Context ctx = new InitialContext();
pool = (DataSource)ctx.lookup("jdbc/pool1");
} catch(Exception e) {
System.out.println("problem with datasource.");
}
} The ejbCreate Method
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
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
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
The code examples shown here are from the EJB Samples directory, which is available with the WLE software.
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 WLE 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> 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.
The following code fragment shows the client application code creating the stateful session bean using the primary class key:
// Give this trader a name The following code example 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.
// The reason the following attribute is public is to test This section provides the following two code examples:
Example Deployment 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
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
// 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
The following example 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.
try { The following code fragment shows a business method from the TraderBean
example, available in the EJB Samples directory provided with the WLE 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.
getStockPrice() and getTradeLimit() methods use DD environment properties to access constant values using JNDI lookup() - prevents hardcoding data.
Client Maintaining Bean's State
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("End of Transaction " + i + "\n"
Stateless Bean Tracking Its Own State
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);
}
}
|
Copyright © 1999 BEA Systems, Inc. All rights reserved.
|