BEA Logo BEA WebLogic Enterprise Release 5.0

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

 

   WLE Doc Home   |   Getting Started   |   Previous   |   Next   |   Contents   |   Index

Designing and Developing Enterprise JavaBeans for the WLE System

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).

Designing EJB Applications for the WLE System

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:

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 following:

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.

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. 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

WLEContext.
INITIAL_CONTEXT_FACTORY

com.beasys.jndi.
WLEInitialContextFactory

Specifies the WLE JNDI.

WLEContext.PROVIDER_URL

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

Defines the address of the entry points to the WLE 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:

WLEContext.
SECURITY_PRINCIPAL

<Principal Identifier>

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

WLEContext.
SECURITY_CREDENTALS

<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 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.

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 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 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 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.

Home Interface Registration

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.

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 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:

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:

Developing EJB Applications for the WLE System

This topics provides the following sections:

Development Steps

The primary steps for developing an EJB are the following:

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).

Step 1: Write or obtain an EJB.

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:

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.

Step 2: Create a deployment descriptor.

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.

Required Elements in the Deployment Descriptor

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.

Element

Description

Purpose

ejb-name

EJB's name

Specifies the logical name you assign to each EJB in the EJB JAR file. There is no architected relationship between this name and the JNDI name that the Deployer assigns to the EJB.

ejb-class

EJB's class

Specifies the fully qualified name of the Java class that implements the EJB's business methods.

home

EJB's home interface

Specifies the fully qualified name of the EJB's home interface.

remote

EJB's remote interfaces

Specifies the fully qualified name of the EJB's remote interface.

session | entity

EJB's type

The EJB types are session and entity . Use the appropriate session or entity element to declare the EJB's structural information.

session-type

Session bean's state management type

Declares whether the session bean is stateful or stateless.

transaction-type

Session bean's transaction demarcation type

If the EJB is a session bean, declares whether transaction demarcation is performed by the enterprise bean or by the container.

persistence-type

Entity bean's persistence management

If the EJB is an entity bean, declares whether persistence management is performed by the EJB or by the container.

prim-key-class

Entity bean's primary key class

If the enterprise bean is an entity bean, specifies the fully qualified name of the entity bean's primary key class. You must specify the primary key class for an entity with bean-managed persistence, and you can optionally specify the primary key class for an entity with container-managed persistence.

cmp-fields

Container-managed fields

If the EJB is an entity bean with container-managed persistence, specifies the container-managed fields.

For complete details about the elements you specify in the standard deployment descriptor, see the EJB XML Reference in the WebLogic Enterprise online documentation.

How to Create the Deployment Descriptor

You can create the deployment descriptor by any of the following methods:

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:

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>
<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.

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.

EJB Examples

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 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.

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 the following table.

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 WLE, 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, and they are also specified in the sample deployment descriptor shown in the section How to Create the Deployment Descriptor.

// 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 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() {
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 1.1 Specification 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. 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)
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 the following fragment specifies the values in those rows.

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

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()
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 WLE 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 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>
<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.

The following code fragment shows the client application code creating the stateful session bean 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

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
// 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

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 {
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

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.

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);
}
}