Charles Schwab and IBM's BeanExtender

by Dave Johnson,
IBM Software Solutions Division


Abstract

This article focuses on Schwab's use of the JavaBeans component model and BeanExtender. Charles Schwab & Co., Inc., and IBM Corporation have jointly developed a Web-based financial portfolio application that uses IBM's new BeanExtender. The application is composed from a number of JavaBean components wired together using BeanExtender's instance-based aggregation model. JavaBeans can be further modified with BeanExtender's "dipping" technology. Because of the success of this prototype application, Schwab is designing and coding more production-level JavaBean components, using BeanExtender in conjunction with IBM's VisualAge for Java. These components are being used to build Web-based, multi-tiered applications.


Partnership Background

Since the fall of 1996, IBM has been working with Charles Schwab to create an interface using JavaBeans. Schwab, the leader in Web-based securities trading, wanted to provide a common interface to its core systems for use by its semi-autonomous business units. At the same time, Schwab wanted to combine the various programming tasks in the core systems unit and also support all the various client and intermediate server platforms, including Web-based platforms. Some of the major clients that needed to be supported were written with ActiveX components. Although Java, JavaBeans, and the Java ActiveX Bridge address most of Schwab's needs, using these technologies in a mission-critical enterprise environment breaks new ground.

The interface is between the core systems, which are managed by an infrastructure group within Schwab, and the business units, each of which deliver client applications using their own programming staffs. In order to minimize the cost of business applications, there is a strict separation between access to the core system and logic and displays on the clients. The client application is assembled from components provided by both the infrastructure group and the business units, which enables the infrastructure group to continually improve the interface. To simplify management of this application, Schwab used BeanExtender's new instance-based programming techniques.

The sections below discuss how Java, JavaBeans, ActiveX, and BeanExtender are used in Schwab's environment; they also discuss how the application structure is supported using data-access parts and viewers with the JavaBeans event model. Then discussed are instance-based programming and the use of dipping to enhance binary classes that provide the core system access with constraints or extensions required by the business unit.


Designing JavaBeans That Work Together

Our example application allows an end user to enter an account ID and obtain information about the corresponding financial portfolio. The application is a Java bean composed from eleven other JavaBeans specifically designed to work together. Two basic bean types are used: data access parts (DAPs) for accessing the back-end database and viewers for graphically displaying the data. The JavaBeans used in the application deal with various aspects of an individual's financial portfolio. These JavaBeans consist of an account ID viewer, an account balance DAP and viewer, an account information DAP and viewer, an account position DAP and viewer, a stock list DAP and viewer, and a ticker tape DAP and viewer. Each viewer and its corresponding DAP are packaged in a standard JAR file (the delivery mechanism for JavaBeans defined by JavaSoft).

But how do we design the Javabeans so that they work well together and are connectable in a builder environment? One method is to use the JavaBean event model–one of the core features of the JavaBeans architecture. The event model works by allowing some components to act as sources for event notifications, while other components act as listeners that receive and handle the events sent from a source component. An application builder can then directly manipulate events and the relationships between event sources and event listeners at design time.

In order for a Java bean to be considered an event source, it must implement both an add and a remove method according to the following predefined design pattern:

public void add<ListenerType>(<ListenerType> listener);

public void remove<ListenerType>(<ListenerType> listener);


where is the listener interface defined for the event. The event source maintains a list of registered listeners obtained from the add method above. When the event occurs, the listeners are notified by the source, which invokes the appropriate method (defined in the listener interface) on each listener. An event object, which encapsulates information that the event source passes to the registered listeners of the event, is sent as a parameter of the method invoked on the listeners.

In order for a Java bean to be considered an event listener, it must implement one or more event listener interfaces and must register itself with corresponding event sources.

Our application uses these JavaBean design patterns to build JavaBeans that are easily connectable in a builder environment. The account ID viewer bean is an event source that provides registration methods; these methods enable an event listener to register and to be notified when a new account ID has been entered and the submit button pressed. The various data access parts are event listener JavaBeans that have been designed to work well with the account ID event source bean. They implement the AccountIDInformationChanged method, which is defined in the AccountIDChanged interface. This method is fired by the account ID source bean when a new account ID is entered.

In order to further clarify these concepts and show how JavaBeans might be connected in a builder environment, let's examine the account ID viewer and the stocklist data access part. Figure 1 illustrates what happens when the account ID viewer and the stock list data access part are brought into a builder environment in preparation for constructing an application. The builder loads both of the JavaBeans into the Java virtual machine. Then the builder uses the bean introspection process to discover which properties, events, and methods a particular bean supports. By following the JavaBean design patterns and using the introspection process, the builder is able to determine that the account ID viewer is an event source for the AccountIDChangedEvent and that the stock list DAP is an event listener for the same event. The builder can then present these two JavaBeans as likely candidates for connection. The application assembler decides whether or not to connect them.


Figure 1. Discovering bean candidates for connection in a builder environment.


Figure 2 shows a case in which the application assembler has decided to connect the account ID viewer with the stock list data access part. In making the connection, the builder generates code for an event adapter class, which acts as a generic "wiring manager" between the account ID viewer source bean and the stock list DAP listener bean. The event adapter implements the EventListener interface expected by the source bean and de-couples the incoming event notifications on the interface from the actual listener.


Figure 2. Connecting JavaBeans using an event adapter.


Figure 3 is a run-time state diagram that shows the sequence of events that occur after the application is built, deployed, and in use. The steps of the state diagram are as follows:

The user enters an account ID and presses the submit button in order to retrieve the corresponding account information. The account ID viewer invokes the AccountIDInformationChanged method on the event adapter because the event adapter registered with the account ID bean as an event listener. The accountIDChangedEvent that contains the account ID number is passed as a parameter of the AccountIDInformationChanged method. The event adapter invokes the AccountIDInformationChanged method on the stock list data access part. The stock list DAP then uses the account ID to query the database for the corresponding account information.


Figure 3. Using the application.


The following source code shows the implementation of the JavaBean event design patterns that we have been discussing.

//---------------------------------------------------------------
// This is the class definition for the event that is fired when
// the new account ID is entered and the submit button is pressed
//---------------------------------------------------------------
public class AccountIDChangedEvent extends java.util.EventObject
{
  public AccountIDChangedEvent(Object source, String accountID)
  {
    super(source);
    this.accountID = accountID;
  }
  public String getAccountID() {return accountID;}
  // read-only parms...
  protected String accountID;
}
//---------------------------------------------------------------
// This is the interface that must be implemented by all event
// listeners interested in the AccountIDChangedEvent.  The stock
// list data access part implements this interface.
//---------------------------------------------------------------
public interface AccountIDChangedListener extends java.util.EventListener
{
   public void AccountIDInformationChanged(AccountIDChangedEvent aIDChanged);
}
//---------------------------------------------------------------
// The following code is from the account ID viewer
//---------------------------------------------------------------
private Vector listeners = new Vector();  // list of listeners
// This is the listener registration method that the event
// adapter invokes in order to register itself as a listener.
public synchronized void addAccountIDChangedListener(AccountIDChangedListener aIDChanged)
{
    listeners.addElement(aIDChanged);
}
// This is the listener registration removal method that can be
// used to un-register a listener.
public synchronized void removeAccountIDChangedListener(AccountIDChangedListener aIDChanged)
{
       listeners.removeElement(aIDChanged);
}
// This is the method that is invoked when the account ID has
// changed and the submit button has been pressed.
protected void fireAccountIDInformationChanged(String accountID)
{
       Vector l;
       // build a new event object passing the account id string
       AccountIDChangedEvent aIDChanged = new  AccountIDChangedEvent(this,accountID);
       // copy the vector in order to freeze the state of the set
       // of EventListeners the event should be delivered to
       // prior to delivery
       synchronized(this) {l = (Vector)listeners.clone(); }
       // notify all registered listeners
       for (int i = 0; i < l.size(); i++) {
         ((AccountIDChangedListener))l.elementAt(i)).AccountIDInformationChanged(aIDChanged);
       }
}
//---------------------------------------------------------------
// The following code is from the stock list DAP 
//---------------------------------------------------------------
// This is the implementation of the AccountIDChangedListener
// interface
public void AccountIDInformationChanged(AccountIDChangedEvent  myEvent)
{
    // Use the account ID in the account ID changed event as a
    // key to access the correct account information in the
    // databae.
}

Just as the account ID viewer has been designed to work well with all of the data access parts, each individual data access part has been designed to work well with its partner viewer. Each DAP is written as an event source, and its corresponding viewer is written as an event listener that implements the interface containing the appropriate method fired by the partner DAP. By following these JavaBean design patterns, we build our JavaBeans in such a way that a builder environment can easily detect which JavaBeans are candidates for connection and can provide a convenient graphical interface that allows us to connect our JavaBeans together into a meaningful application.


Assembling The Instance-Based Application

BeanExtender supports the building of applications or applets through simple aggregation of instances of Javabeans. In contrast to many other aggregation models, BeanExtender does not generate hard-coded connections or states for the aggregated JavaBeans; instead, it builds up an aggregated instance of multiple bean instances. This aggregated instance retains its customized state via persistence through serialization. The persistent aggregate state can be updated later or a new persistent state can be created from a modified aggregate without regenerating code.

Although the current plan is for BeanExtender to be integrated into various other IBM products that may contain their own builder environments, the current stand-alone version provides an Assembly Surface builder tool that can be used to demonstrate various aspects of the technology. The Assembly Surface was used to connect and build our instance-based application.

The first thing that we must do in building our application is to load all of the individual Java bean components into the Assembly Surface. The Assembly Surface uses BeanExtender's ManagedBean, which supports the loading of JavaBeans from JAR files, directories, ZIP files, or network repositories. Our JavaBeans are packaged in six different JAR files. Note that one JAR file contains the account ID viewer, and the other five JAR files each contain a viewer and its related DAP; that is, the tickerTape.jar file contains the ticker tape viewer and the ticker tape data access part.

The next step in building our application is to lay out and assemble the individual JavaBeans that we just loaded into the Assembly Surface environment. The Assembly Surface contains a number of different views that can be used to facilitate the building of an application, and we are especially interested in three of those views: the JavaBeans view, the layout view, and the event connections view.

The JavaBeans view allows us to look at all of the JavaBeans contained in an individual repository and to select any number of those JavaBeans to be added to the contents list in the Assembly Surface. Once a bean has been selected and added to the contents list, an instance of the bean is created and can be customized. One example of customization is the positioning and sizing of the GUI representation of a visible bean; this customization is done in the layout view. Note that some JavaBeans (our data access parts are examples) are non-visible JavaBeans and will not appear on the layout view.

Besides selecting and customizing the JavaBeans that are to be part of the application, most applications will also need to connect the JavaBeans together in some meaningful fashion. As described earlier, we have coded our JavaBeans using the JavaBean event design patterns so that they will logically fit together and so that the Assembly Surface will be able to provide us with an event connections view that will allow connections to be made easily. Basically, the event connections in our application involve connecting the account ID viewer to each individual DAP and then connecting each DAP to its corresponding viewer (see Figure 4). The end result is that when an account ID is entered and the submit button is pressed, an event is sent to all of the data access parts, which then use the account ID to look up the corresponding information for that account. The DAPs then send that information via another event to the corresponding viewer, which will then graphically display it. In this manner, all of the eleven JavaBeans for our application are instantiated, the visible JavaBeans are layed out, and all event connections are made.


Figure 4. Event flow connection diagram for the application.


Finally, the application can be generated as either an application or an applet by building up an aggregated instance of the multiple bean instances ( see Figure 5, which displays the working application) into a new complex bean instance. This instance-based programming model is also the basis for BeanExtender's "Bean Dipping" technology, which is discussed in the next section.


Bean Dipping Teaches Old JavaBeans New Tricks

One of the most powerful technologies included with BeanExtender is that of Bean Dipping. This technology enables the user to add, delete, or modify the behaviors of existing JavaBean components without having access to the source code of the original bean and without having to continuously regenerate code. Behaviors can be dynamically added throughout the component life cycle (development, deployment, and run-time execution) with direct modification of the existing JavaBean components.

In order to be able to modify and extend the existing behaviors of a JavaBean component, we must first go through a process we call "morphing." This process involves taking the original bean and using JavaBean Introspection to access and then wrapper that JavaBeans' events, methods, and properties, thereby producing a new version of the bean that retains its original identity but that has now been made "trainable." The bean may be wrappered using inheritance, in which all non-private events, methods, and properties are wrappered, or it may be wrappered using aggregation, in which only the methods associated with a particular interface are wrappered. The JavaBeans' behavior may now be enhanced, inspected, or restricted, depending on the particular "dip" applied.

Schwab wanted session authentication to be added, so that a user ID and password must be entered before access is allowed. None of the JavaBeans used to build the application could do this originally, however; this feature was added through the dipping process by morphing the account ID viewer, instantiating that bean by adding it to the contents list, applying a session authentication dip to that particular instance, and building the rest of the application in the normal fashion. Note that since we are dealing with instance-based programming, it is easy to build different versions or instances of the application containing different behaviors. The dipping process can be done through the Assembly Surface or through a utility shipped with BeanExtender.

Although BeanExtender comes with a number of sample dips, such as session authentication, version control, printing, tracing, and licensing, it is expected that many development groups will want to write their own custom dips appropriate to their situation. Using the dipping framework, using the sample dips as examples, and reading the documentation should make this a relatively simple process.

Dips come in two main flavors: behavior modification dips that modify the behavior and semantics of the dipped bean (for example, security may check every method, property, and event for access privilege), and extension dips that extend the external interface of the bean. One important use of dipping is in implementing new or changing business logic. Business rules can be implemented as independent dips to be dynamically applied, customized, and removed from live business objects. For example, the results from a database query could be filtered depending upon the business rules dip that has been applied to the particular application instance.


BeanExtender Makes JavaBeans Better

Through our discussion of the joint application work done by Charles Schwab and IBM, we have demonstrated numerous ways in which BeanExtender can make JavaBeans better. Many BeanExtender features have been presented, including the ManagedBean class, the instance-based aggregation model, "Bean Dipping," and the Assembly Surface builder tool.

Schwab is able to migrate to JavaBeans in increments and to maintain investments in ActiveX. The ActiveX bridge allows JavaBeans to be wrapped so that they will work in ActiveX containers such as Visual Basic and Microsoft Excel. In fact, all of the JavaBeans described in this article were wrapped using the bridge, and the complete application was assembled and run in the Visual Basic environment.

The latest version of BeanExtender is now available for downloading on the IBM alphaWorks Web site. Follow-up versions will be available in future releases of the IBM VisualAge WebRunner Toolkit subscription service. For details, see the WebRunner Web site. The BeanExtender Technology Application Development Web site is an excellent source for the latest information. IBM plans to integrate BeanExtender into future releases of the VisualAge product family, including VisualAge for Java and other tools.
About the Author

Dave Johnson is a software engineer at IBM in Austin, Texas. Mr. Johnson has worked on a variety of projects during his tenure at IBM, concentrating in the areas of object-oriented development and consulting. Recently he has been working as a developer with the BeanExtender team and working with Charles Schwab, prototyping the application described in this article. Mr. Johnson holds a master's degree in computer science, as well as a second master's degree in music performance and literature. He is a prolific inventor; he has had five patent applications filed and fifty articles published in the IBM Technical Disclosure Bulletin. Mr. Johnson can be reached at
kdjohn@us.ibm.com.




Java is a trademark of Sun Microsystems, Inc.

Other companies, products, and service names may be trademarks or service marks of others.

Copyright    Trademark



  Java Feature Java Home  
IBM HomeOrderEmployment