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