Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Online Training

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Training Index

Introduction to the JavaBeans API
Short Course

by John Zukowski, MageLang Institute

[About This Short Course | Magercises]

This module will teach you how to use the JavaBeansTM API to create independent, reusable, platform-independent, marketable components with JavaTM technology.

Course Outline

Overview of JavaBeans Technology

A JavaBeans component is an object that conforms to a communication and configuration protocol, as prescribed by the JavaBeans specification. The JavaBeans specification prescribes programming conventions and dynamic discovery mechanisms that (1) minimize the design and implementation effort for small software components while (2) fully supporting the design, implementation, and assembly of sophisticated components. The three fundamental aspects of the JavaBeans component as defined by the specification are events, properties, and methods.

The success of the JavaBeans model is due in large part to its "division of labor" strategy. Consider the design of a common graphical component such as a progress bar. The fundamental task of displaying a percent-completion bar is quite easily handled with basic drawing operations. With the JavaBeans model, you can implement a basic progress bar Bean in 200 lines of code or less. That is, with respect to design and implementation, the model does not impose any significant up-front overhead. In other words, the overhead is minimal.

Much of the JavaBeans API is optional. Supplemental tasks such as supporting configurable foreground and background colors, vertical or horizontal configuration, and increment size are easily handled with minimal programming effort due to various API conventions. For tasks such as providing a sophisticated, custom color editor, the JavaBeans API comes to the rescue with a variety of supporting interfaces and classes—all optional.

The JavaBeans architecture, a modern component architecture, is designed for building independent software components from which programmers assemble larger application components. With JavaBeans components, programmers have total freedom to assemble components using traditional programming strategies or to use graphical builder tools to connect JavaBeans components, or to combine both techniques.

The JavaBeans architecture is the standard component architecture for Java technologies. The complete JavaBeans API is packaged in java.beans, one of the core Java APIs. This package includes interfaces and classes that support design and/or runtime operations. In developing a JavaBeans component, it's common to separate the implementation into design-only and runtime classes, so that the design-oriented classes (which assist programmers during component assembly) do not have to be shipped with a finished application. The JavaBeans architecture fully supports this implementation strategy.

There are additional supporting APIs available. The Glasgow specifications define the principal new JavaBeans capabilities. Parts of this specification are incorporated into the Java 2 platform, version 1.2, for example, the drag and drop subsystem; other facilities are available as a Standard Extension, for example, the JavaBeans Activation Framework, which defines standard mechanics for Bean instantiation and activation.

The InfoBus specification defines a secondary API that provides yet another, possibly alternative, communication mechanism among Beans. The InfoBus provides programming conventions and mechanics whereby JavaBeans components can register with either a default or a named "information bus." Components cooperate by getting on the same bus and exchanging information following an asynchronous (event-driven) communication protocol.

The core/standard JavaBeans API is a fairly lightweight component architecture. The discussion here focuses on standard JavaBeans programming. You, of course, can track upcoming developments in the Glasgow and InfoBus APIs via the previously mentioned websites.

Introduction to Beans Technology

Component technology's time has come. The concept of designing applications by plugging together components has lingered in programmers' minds for 30 years, since M. D. McIlroy (1968) made a now-historical plea for catalogs of software components. The practical tools necessary for McIlroy's vision of libraries of software components now exist, fundamentally with the core Java programming language, but also in the JavaBeans API for client-level component assembly, and the Enterprise JavaBeans specification for server-level component assembly.

For the last 30 years, programmers have swayed to and fro on the component issue, drawn in one direction by management's continued reliance on outdated technologies and in the other by a series of programming developments that include languages such as Smalltalk, Eiffel, and now the Java programming language. The recent shift in programming paradigms, attributable in part to Internet developments, has forced component technology out of the shadows. There is, finally, light at the end of the tunnel—it's a great time to be a programmer.

Component technology in the 1990s incorporates the event-driven methodology of the late 1980s. Software components support synchronous communication via method calls. In addition, components communicate asynchronously using an event and notification model that's often characterized by terms like subject-observer or source-target.

Principally, Beans are source objects. Typically, a Bean does its work and, at times, sends notifications of changing state to all registered targets. These notifications are component-specific; that is, they signal the occurrence of one or more significant events in the Bean instance. In a drop-down list, for example, selecting an item would constitute such an event.

Hence, interested parties, for example, a phonebook application, can register with the source object for event notifications and perform their own component-specific operations in response to these events, for example, dialing the telephone number selected in the drop-down list.

As another example, the following worksheet from Sun's demonstration JavaBeans tool, the BeanBox, illustrates a Progress Bean as well as ProgressTarget, a primitive target Bean designed simply for testing Progress Beans:

A Progress instance reports each change in its progress-completion value as an event to all registered targets. A ProgressTarget instance registers for these events and displays each new progress-completion value.

Many enterprises are now designing libraries of JavaBeans components because the event-driven approach to software components forces designers to think in terms of published, significant events, as opposed to simply implementing a zillion methods for controlled, synchronous access to an object's current internal state. The JavaBeans approach works because (1) it reduces the surface area of the component API and (2) it's conducive to component assembly and connection with integrated development environments (IDEs), graphical builder tools, or RapidApp tools, whatever your preferred terminology.

In many cases, a JavaBeans component will function as a source for certain types of events, yet be capable of registering as a target for events produced by other components. For example, a heating and cooling unit controller would typically register with a thermostat component for notification of temperature changes (temperature-change events) and at the same time function as a source for heating and cooling unit on-off event notifications to multiple heaters, boilers, coolers, and/or air conditioners. See the controller registered as targets[3] in the following scenario:

The upcoming sections address the issues involved in designing a JavaBeans component with one or more event notification schemes and basic configuration support, as well as providing customized configuration controls within an IDE.

Just What is The JavaBeans API

The JavaBeans API includes several interfaces and classes in the java.beans package. In addition, it employs interfaces and classes from other Java technology API areas including:

  • The Java event model: java.util.EventObject, java.awt.event
  • Object serialization: java.io.Serializable, java.io.Object*
  • Reflection: java.lang.reflect

The Java Development Kit (JDKTM) 1.0 included the AWT (Abstract Window Toolkit) for graphical user interface (GUI) implementation. This version of AWT used a containment model for events. That is, GUI events were generated on a component-by-component basis and any and all events that were not "handled" within their "home" component propagated upward or outward to the surrounding container.

At each containment level, unhandled events propagated to the next level until eventually unhandled events propagated to the outermost container. This outermost container was, of course, some specialization of Window, typically, either a Frame or Dialog instance. At this level, unhandled events simply disappeared into oblivion.

The containment model had several problems:

  • By default, all common events were reported but often went unused, hence, a waste of computing cycles
  • To process events of interest, programmers had to either:
    • Subclass the GUI component class and override the appropriate event-related method
    • Capture the events after they propagated outward to the surrounding container using (messy) case analysis
  • Events did not exist outside the GUI framework

JDK 1.1 introduced the subject-observer or source-target event model. JDK 1.1 provides base-level support for this event model outside the AWT package, specifically, in the java.util package. The relevant interface, class, and exception are java.util.EventListener, java.util.EventObject, and java.util.TooManyListenersException.

With this approach, programmers can use event-driven communication strategies above and beyond either GUI or JavaBeans contexts, for example, thermostats communicating with heating and cooling unit controllers. Ideally, however, nongraphical event-driven scenarios should take advantage of the JavaBeans framework, because the JavaBeans component API is now well known and supported by many IDEs.

In most cases, however, the JavaBeans API is used for designing graphical components. The source-target event model is ideally suited for graphical events such as mouse pointer motion, mouse button clicks, key activity, and high-level component operations such as pressing a command button and selecting items from a drop-down list. In fact, all AWT components employ the JavaBeans framework for asynchronous event communication, as well as for configuration support; that is, all AWT components are fully compliant JavaBeans components. While the AWT components include support for the original JDK 1.0 event model, components created to use the JavaBeans framework cannot use the older model.

Object serialization is another core Java API area that is indispensable for basic JavaBeans functionality. When programmers assemble, configure, and connect Beans using an IDE, the JavaBeans components must be "live," dynamically created objects. The IDE must be able to save the worksheet's state at the end of the day and restore it at the start of a subsequent session. That is, a Bean's state must persist via external storage.

JavaBeans components, like all other user-defined data types in the Java environment, support persistence by implementing the Serializable interface. Serializable is a tagging interface; that is, it marks an object as suitable for serialization by the Java runtime environment.

Before attempting to write an object to disk (or send it over the network) as a serialized byte stream, the Java interpreter verifies that the object implements Serializable. Take for example, a worksheet such as the one with connected, operational Progress and ProgressTarget Beans shown in the previous example. For an IDE to save the state of the worksheet, it would use selected java.io.Object* classes to serialize the subsequently deserialize the worksheet contents (along with other IDE- and project-related information).

Reflection is the third indispensable API (java.lang.reflect) for the JavaBeans architecture. With reflection, it's straightforward to examine any object dynamically, to determine (and potentially invoke) its methods.

By examining a Bean dynamically to determine its methods, an IDE can analyze design patterns in method names and put together a list of access methods that retrieve and set instance data, for example, getForeground() and setForeground() for retrieving and setting foreground color. With the JavaBeans API, an instance/state variable with this type of pairing of access methods is called a property.

Thus, when a programmer drags and drops a JavaBeans component from an IDE's palette onto a worksheet, the IDE uses reflection to determine the Bean's properties and present them for editing in a graphical window, commonly called a property sheet. The main point, however, is that by using standard naming conventions a programmer can design a Bean that's configurable in a graphical builder tool with minimal attention to configuration-related details. This somewhat-automatic, somewhat-default support for configuration is possible due to Java technology's reflection mechanism, in particular, and due to Java technology's dynamic nature, in general, both of which exist outside the JavaBeans paradigm.

JavaBeans Design Issues

JavaBeans objects are like other user-defined data types, but with the following additional options that make the objects more useful:

  • Providing a public no-argument constructor
  • Implementing java.io.Serializable
  • Following JavaBeans design patterns
    • Set/get methods for properties
    • Add/remove methods for events
      • Java event model (as introduced by JDK 1.1)
  • Being thread safe/security conscious
    • Can run in an applet, application, servlet, ...

For an IDE to instantiate a bean, the class implementation must provide a no-argument constructor. An example of this would be when a developer drags a component from the palette and drops it into the design worksheet. After several bean assembly, connection, and configuration operations, at some point, the IDE will need to save the bean as part of a project. For this to take place, the bean must be serializable.

For an IDE to automatically present various state variables for configuration/editing, there must be access methods that follow prescribed naming, return value, and signature conventions—the JavaBeans design patterns.

This design pattern principle applies to events as well. For an IDE to allow communication connections between Beans, there must be add and remove methods that the IDE can invoke to register and unregister targets (Beans that listen to and respond to event notifications). That is, an IDE must be able to connect the event notifications from one Bean to the event-handling functionality of another Bean, typically, using a graphical, rubberband-like point-and-connect strategy.

Lastly, the Java programming language supports multithreading and the Java runtime environment is a multithreaded world. Screen-updating threads asynchronously invoke a Bean's paint() method, which typically is dependent of certain state variables, which in turn are often settable through a property sheet. With the Java environment, all user-defined classes should be thread-safe; this requirement is especially significant with JavaBeans.

In some case, "bean-ifying" a user-defined data type leads to additional design considerations. For example, suppose a class implements a graphical label widget, like AWT's Label except with multiline support. The following Bean, FlexLabel, implements this functionality:

To allow the user to set the label (property), both programmatically and within a Bean-aware IDE, you must have a strategy for representing line breaks. This simple implementation of FlexLabel uses the HTML "<br>" tag. This type of text-and-linebreak representation is mandatory for programmatic invocation of the setLabel() method, but only minimally sufficient within the property sheet.

Typically, you would provide a Bean support class that implements a custom property editor, for example, something similar to the multiline text object below, solely for use during design-time operations within an IDE:

The point is that in most cases you must support both mechanisms for modifying such a state variable.

Each JavaBeans component will have its own specific design issues. Thus, going beyond a standard user-defined data type implementation and implementing a class as a Bean typically implies a little additional work. In most programming environments, the extra work is easily justified because of the added ease of use for programmers of all backgrounds.

Magercises

  1. The Beans Development Kit
  2. Working with Beans

JavaBeans Event Model

As mentioned, JavaBeans uses the Java event model to communicate. Events provide an alternative to (synchronous) method invocations for any type of communication between components in which "background notifications" are appropriate. That is, components providing one or more computational services can acknowledge and handle other services on an event-driven, or asynchronous, or "logical interrupt" basis.

For example, consider a software component that principally provides telecommunications data analysis. You can design this component to "listen" for incoming-data notifications, adding new satellite data to its model on an asynchronous basis. In this case, the data processing component is a target of some other software component that announces the availability of data. With respect to the data processing component, the data collection and deliver component is a source for telecom data.

In an event-driven paradigm, the source and target orientation is a matter of context. A component can be a source for one type of event and a target for another. With JavaBeans, you're almost always implementing some type of source functionality—for significant events such as temperature changes, progress-bar state changes, and so on.

In general, event-driven designs are ideal for a variety of tasks:

  • Handing user interface events:
    • Mouse actions
    • Keyboard events
  • Managing/reporting inter-client connections:
    • JDBC Bean that connects to database server
      • Notifies a client of specific changes in a database
      • Accepts database requests and notifies a client when the data is available
  • Other events:
    • Property changes in a Bean
    • Any general-purpose notification from one object to another

An event occurrence, as defined by the JavaBeans component (as the source), is typically followed by some type of event notification. The event notification process passes along pertinent event-related data to each registered target in a specialized event object. java.util.EventObject is the base class for event objects.

New subclasses of EventObject specialize java.util.EventObject for Bean-specific event types:

  • Example: "employee-has-been-hired" event
  • Example: "smiley-face-mood-changed" event
  • Example: "stick-figure-body-parts-changed" event

Event objects carry pertinent/timely data to registered targets; this data is typically read-only. Therefore, the target object uses the event object's access methods to retrieve data.

Consider the following stick-figure Bean example:

Its event object could be defined as follows:

public class StickFigureEvent extends EventObject {
  private StickFigure source;
  private long date;
  public StickFigureEvent(Object source) {
    super(source);
    this.source = (StickFigure)source;
    date = System.currentTimeMillis();
  }
  public long getDate() {
    return date;
  }
  ...
}

The implication of this minimal, generic event notification is that some significant event has occurred and the target object can use the getDate() access method to determine exactly when it occurred. But, for any additional information regarding the source and/or recent events, the target would have to discover what happened by using the source's standard access methods. Did the stick figure's mood change from a smile to a frown? Did the stick figure's waistline change?

In designing a JavaBeans component, it's important to allow sufficient up-front design time for creating multiple, specialized event objects for fine-grained communications regarding state changes in the Bean. That is, how well does the Bean "express itself?"

With component technology such as Beans, there must be a way for a Bean to say "I'm active; I'm doing various things such as X, Y, and Z; who's interested?" And, target objects must be able to say, "I'm interested in Y; let me know every time you do Y."

With JavaBeans, a source publishes its "monitorable" behaviors using interfaces called event listeners. The interfaces prescribe one or more methods that the source will invoke when the appropriate event occurs. The target implements the interface and the source notifies the target of the significant event by invoking the target's method.

StickFigureListener is an interface that uses the rather generic StickFigureEvent object:

public interface StickFigureListener
    extends java.util.EventListener {
  public abstract void
    stickFigureChanged(StickFigureEvent e);
}

In designing a JavaBeans component, you must choose the events for which the Bean will issue notifications, as well as the structure and syntax for the event object(s) and event notification method(s). You may report different kinds of events through different listener interfaces, each with a single method, for example, stickFigureChanged(), or stickFigureMoodChanged(), or stickFigureSunburnChanged(), or whatever. If appropriate, however, a single listener interface can bundle together multiple notifications methods; consider StickFigureBodyPartsListener:

public interface StickFigureBodyPartsListener
    extends StickFigureListener {
  public abstract void
    neckChanged(StickFigureEvent e);
  public abstract void
    trunkChanged(StickFigureEvent e);
  public abstract void
    leftArmChanged(StickFigureEvent e);
  ...
}

Ultimately, the level of granularity with respect to event notifications is up to the Bean designer.

For a Bean to notify a target via the prescribed method call(s), the Bean must have a reference to the target. Beans support target registration and unregistration with add/remove methods:

public void 
  addAnEventListener(AnEventListener x);
public void 
  removeAnEventListener(AnEventListener x);

For example, StickFigure could support targets with an interest in body-part-change notifications via the following methods:

public void addStickFigureBodyPartsListener(
  StickFigureListener listeningObject);

public void removeStickFigureBodyPartsListener(
  StickFigureListener listeningObject);

Note that any target that registers an interest in StickFigure events by passing its object reference via these methods must implement the appropriate method(s) (the Java programming language is strongly typed).

Another point is that the previous example uses a rather specific listener, in conjunction with a rather generic event object. This approach may or may not be appropriate; it simply depends on the design and function of the Bean. With many Beans, different event classes may be justified for different event types.

Beans must, of course, keep track of the targets that register and unregister, so they can notify the targets when an event occurs. It's common to store each target's reference in a vector, for example,

private Vector targets = new Vector();
...
public synchronized void
    addStickFigureListener(StickFigureListener l) {
  targets.addElement(l);
}
public synchronized void
    removeStickFigureListener(StickFigureListener l) {
  targets.removeElement(l);
}
...

Thus, whenever the event occurs, the notification process is straightforward. It simply traverses the vector and invokes the target's listener method:

protected void notifyTargets() {
  Vector l;
  StickFigureEvent s = new StickFigureEvent(this);
  synchronized(this) {
    l = (Vector) targets.clone();
  }
  for (int i = 0; i < l.size(); i++) {
    StickFigureListener sl =
      (StickFigureListener) l.elementAt(i);
    sl.stickFigureChanged(s);
  }
}
...

Note that it's important to synchronize access to the vector of target objects during registration, unregistration, and notification operations so that the vector doesn't change during direct processing. In the previous example, the notification method synchronizes on the entire source object, makes a copy of the target vector, and then operates on the copy. Another option is to utilize the javax.swing.event.EventListenerList object that comes with the JFC/Project Swing classes.

Sometimes, depending on the design of the source, it's appropriate to limit registration to a single target. If so, the appropriate way to enforce this restriction is to throw a TooManyListenersException instance whenever a target attempts to register and the source is managing an existing target:

public void     
  addSomeEventListener(SomeEventListener x)
    throws java.util.TooManyListenersException;

Lastly, as a convenience to other programmers using the bean, it's common to provide an adapter class for each listener interface that packages multiple notification methods. The adapter class simply provides null-body implementations for each method in the interface, so that programmers interested in only one method notification in the interface can extend the adapter class in lieu of implementing the interface. For example, for the body-parts listener interface, the adapter class would be:

public class StickFigureBodyPartsAdapter implements 
    StickFigureBodyPartsListener {
  public void neckChanged(StickFigureEvent e) {};
  public void trunkChanged(StickFigureEvent e) {};
  public void leftArmChanged(StickFigureEvent e) {};
  ...
}

Thus, a programmer implementing a target can simply specialize StickFigureBodyPartsAdapter, overriding the null-body implementation for the method of interest. Depending on the target, the adapter class mechanism is sometimes not useful, because the target class implementation may already be extending some other class, in which case the target class must implement the listener interface to provide the functionality.

Properties

Properties are the public attributes of a Bean that affect its appearance or behavior, for example, background color, foreground color, font, and so on. For a thermostat Bean, the temperature change notification interval might be designed as an integer property, say, one degree Celsius or three degrees Fahrenheit. For a stick-figure Bean, whether or not the Bean instance is sunburned could be a boolean property.

IDEs typically present properties in a property sheet (dialog box) for editing:

Simple Properties

By default, properties are determined from get/set access method combinations that follow a prescribed naming convention:

public void setXXX(TYPE value);
public TYPE getXXX();

The name of the property is the common part of the get/set method names, that is, the characters following "get" or "set".

For the StickFigure Bean, mood (happy or sad) could be a property:

public void setMood(int mood) {
  this.mood = mood;
  repaint();
}
public int getMood() {
  return mood;
}

By default, IDEs analyze Beans for all conforming properties, organize them in a property sheet, and automatically handle the data conversions required to display their values and process modified values. For example, an integer property is typically converted to a string and displayed in a text field widget. When the value is updated via the property sheet, the IDE must convert the new value to an integer and invoke the appropriate set method. The IDE facilities for managing these property updates are called property editors. Most IDEs provide several built-in property editors.

The previous example illustrates a common property type issue. IDEs provide property editors for common data types. With a property such as mood, the best data types for representing its range of values are often strings or integers. String handling can be quite messy programmatically and, in an IDE, string data types for discrete-valued properties are subject to incorrectly typed (misspelled) values. For this reason, programmers often use integers for properties with discrete values:

public static final int HAPPY = -1;
public static final int SAD = -2;
...
private int mood = HAPPY;
...

For programmatic manipulation of a Bean, this design works well, but for design-time manipulation in an IDE, having to know that happiness is represented by -1 compromises the higher level approach to building applications. For properties such as mood, the preferred technique is to design a custom property editor that accompanies the Bean class, which is discussed subsequently.

For completeness, two secondary issues related to naming conventions should be mentioned. First, the JavaBeans model does not preclude read-only and write-only properties, identified by get-only and set-only access methods, respectively. However, one-way properties are rather uncommon, and, of course, cannot support the typical display-and-update behavior in a property sheet. The second issue has to do with a second type of property, indexed properties.

Indexed Properties

Besides simple properties, the JavaBeans model supports indexed properties. Although uncommon, any object state/characteristic that fits well with the indexed-value model will be recognized as long as you observe the following naming conventions for access methods:

public void setXXX(int index, type value);
public type getXXX(int index);
public void setXXX(type values[]);
public type[] getXXX();

One example of a property that fits this model is color values:

public void setColorTable(int index, Color value);
public Color getColorTable(int index);
public void setColorTable(Color values[]);
public Color[] getColorTable();

Bound and Constrained Properties

The JavaBeans model supports two variations on standard properties: (1) bound properties and (2) constrained properties. Bound properties support the registration and notification of "interested parties" whenever the value of the property changes. Constrained properties take this notification model one step further, allowing the notified party to exercise a veto, to prevent the property change. Unlike with event handling, most of the functionality required to support bound and constrained properties is handled by the JavaBeans framework.

Bound properties are useful for Beans that want to allow instances of the same Bean class or some other Bean class to monitor a property value and change their values accordingly (to match the "trend setting" Bean). For example, consider a GUI Bean that wants to allow other GUI Beans to monitor a change in its background color to update their backgrounds accordingly.

Implementing a bound property is quite easy because of the underlying framework provided by the JavaBeans architecture. To support a bound property, the Bean class must instantiate an object in the JavaBeans framework that provides the bulk of this functionality, and implement registration and unregistration methods that simply invoke the appropriate methods in the JavaBeans framework.

private PropertyChangeSupport changes = 
  new PropertyChangeSupport(this);

public void addPropertyChangeListener(
    PropertyChangeListener p) {
  changes.addPropertyChangeListener(p);
}

public void removePropertyChangeListener(
    PropertyChangeListener p) {
  changes.removePropertyChangeListener(p);
}

Then, each bound property must invoke the firePropertyChange() method from its set method:

public void setMood(int mood) {
  int old = this.mood;
  this.mood = mood;
  repaint();
  changes.firePropertyChange("mood",
    new Integer(old), new Integer(mood));
}

At this point, the PropertyChangeSupport object takes over and handles the notification of all registered targets. Note that PropertyChangeSupport provides general-purpose functionality following a prescribed protocol. Specifically, the method invocation for firePropertyChange() must provide the property name, as well as old and new values, which are passed along to notified targets.

The listener (target object) must provide a propertyChange() method to receive the property-related notifications:

public void propertyChange(PropertyChangeEvent e) {
  // ...
}

Constrained properties add the functionality that the notified listener can object to the property change and execute a veto. To support constrained properties the Bean class must instantiate the JavaBeans object that provides this service, namely, VetoableChangeSupport, and implement the corresponding registration-related methods:

private VetoableChangeSupport vetoes = 
  new VetoableChangeSupport(this);

public void addVetoableChangeListener(
    VetoableChangeListener v) {
  vetoes.addVetoableChangeListener(v);
}

public void removeVetoableChangeListener(
    VetoableChangeListener v) {
  vetoes.removeVetoableChangeListener(v);
}

Note that a Bean could provide one or more bound and one or more constrained properties, in which case it must instantiate both PropertyChangeSupport and VetoableChangeSupport and provide both sets of registration-related methods. In addition, constrained properties tend to also be bound, but that is not a strict requirement.

The set method for bound-constrained properties is slightly more complicated:

public void setMood(int mood)
    throws PropertyVetoException {
  vetoes.fireVetoableChange("mood",
    new Integer(this.mood), new Integer(mood));
  int old = this.mood;
  this.mood = mood;
  repaint();
  changes.firePropertyChange("mood",
    new Integer(old), new Integer(mood));
}

Specifically, the set method must accommodate the exception PropertyVetoException. Also, the sequence of operations is:

  1. Fire the vetoable change notification
  2. Update the appropriate state variables
  3. Fire the standard property change notification, if bound

A veto-interested target object must implement the vetoableChange() method:

public void vetoableChange(PropertyChangeEvent e)
    throws PropertyVetoException {
  // ... 
}

It exercises a veto by (1) including a throws clause for PropertyVetoException and (2) raising the exception (throw new PropertyVetoException();), as appropriate.

The JavaBeans framework receives the propagated exception and in turn propagates it to setMood() via the fireVetoableChange() invocation. Note that setMood() is organized such that in the event of a veto (1) it does not handle the exception (instead, returning and propagating the exception), hence, (2) it does not complete the update to state variables or the property notification for bound-property listeners.

It's clear that the JavaBeans framework supports a lot of property-related functionality and requires minimal work from the Bean implementation.

Magercises

  1. The StickFigure Bean with Properties
  2. The StickFigure Bean with Control Methods

Introspection and BeanInfo

The Java programming language is dynamic. A class instance "knows" its data type, the interfaces it implements, and the data types of its instance variables. An object can discovery many things about objects for which it has a reference, for example, an object's methods and the methods' parameters and return types. With this information, an object can instantiate an object and formulate a method call on the fly, which provides more flexibility than source code-level, compiled object instantiations and method invocations.

In general, this process of discovering an object's characteristics is called introspection. The JDK provides a collection of classes and interfaces for introspection and dynamic manipulation of objects, commonly known as the Reflection API. Reflection is one of the core Java APIs and is packaged in java.lang.reflect. Reflection is covered in a separate MageLang course module.

IDEs use the Reflection API to instantiate an object dynamically when a programmer drags and drops a Bean's icon from a palette to a worksheet. The IDE must be able to instantiate the Bean, as well as discover its properties for inclusion in the property sheet.

The Reflection API supports very general, low-level examination of objects. The JavaBeans framework provides a higher level class, Introspector, that's used by an IDE when working with Beans. An Introspector object assists in discovering a Bean's configurable characteristics. Developers who use the JavaBeans architecture don't typically directly use Introspector, but their IDE environment does use it.

The Introspector class provides functionality for a container to discover information about a Bean, either by directly querying the Bean or from working with a complementary Bean configuration class that optionally accompanies each Bean. This complementary, support class is called a bean-info class. The JavaBeans framework provides the interface BeanInfo, which describes the services that bean-info classes implement, for example publishing the list of configurable properties or defining an alternative way of specifying accessor methods. An Introspector object manipulates and makes available a Bean's configuration services in a general-purpose manner using the BeanInfo interface. When there is no bean-info class, the Introspector object uses reflection to discover a Bean's properties.

There are a variety of configuration possibilities with Beans: properties, property editors, custom configuration dialog boxes, and so on. A Bean publishes its configuration support via methods in its bean-info class. A Bean analyzer then instantiates the bean-info class and queries the appropriate method during the Bean configuration process.

A Bean analyzer searches for a bean-info class by appending "BeanInfo" to the Bean's class name, for example,

  • MyWidgetBeanInfo
  • TextFieldBeanInfo
  • StickFigureBeanInfo

Each IDE is free to design its own Bean analyzer class(es), but in all cases the operation would be similar to:

TextField tf = new TextField();
BeanInfo bi = 
  Introspector.getBeanInfo(tf.getClass());

Any object that implements the BeanInfo interface meets the data type requirement implied in the previous code.

At times, no bean-info class is required; it's sufficient to provide standard, bound, and constrained properties following the naming conventions outlined previously. At other times, it's sufficient to provide one or two configuration specifications, for example, to restrict the number of properties displayed in the property sheet or provide a custom property editor. For a StickFigure Bean, it might be important to provide a drop-down list for setting the mood property.

As a convenience for the developers who use the JavaBeans architecture, the JavaBeans API provides SimpleBeanInfo, a class that implements BeanInfo with empty-body methods. You simply override the appropriate methods with implementations that build and return the appropriate configuration data.

For example, consider StickFigureBeanInfo:

import java.beans.*;
public class StickFigureBeanInfo
    extends SimpleBeanInfo {
  public PropertyDescriptor[]
      getPropertyDescriptors() {
    try {
      PropertyDescriptor pd1 = new
        PropertyDescriptor("mood",
          StickFigure.class);
      pd1.setBound(true);
      pd1.setPropertyEditorClass(MoodEditor.class);
      PropertyDescriptor pd2 = new
        PropertyDescriptor("sunburned",
          StickFigure.class);
      pd2.setBound(true);
      return new PropertyDescriptor[] {pd1, pd2};
    } catch (Exception e) {
      return null;
    }
  }
}

In the previous example, MoodEditor is a class that implements a drop-down list for the mood property.

Magercise

  1. The StickFigure Bean with BeanInfo Support

Nongraphical Beans

There is nothing about the JavaBeans framework that implies that Beans should be graphical objects such as command buttons and drop-down lists. A good rule of thumb is that if it makes sense to drag and drop an object from a palette to a worksheet as part of the application development process, it makes sense to implement the object as a Bean.

From the previous sections, it's clear that "Bean-ifying" a class can be quite simple because of the default Bean functionality. Minimally, you must provide a no-argument constructor, implement the Serializable interface, and so on as described previously.

The Bean framework is often overlooked for its value in debugging and testing new classes. You can add simple properties that turn on debugging mode, or initiate arbitrary operations when you change a boolean property's value from false to true ("off" to "on"). Manipulating application state in this manner is often simpler than writing a test GUI that allows you to submit test values for processing.

Subsequent sections use a nongraphical Hire Bean to reinforce this idea and to illustrate Bean customization. The Magercises apply the customizations illustrated with Hire to the graphical StickFigure Bean, and others. The remainder of this section introduces the Hire Bean.

Hire is a simple Bean that simulates employee hiring operations. For clarity, the Hire implementation is very minimal, but it could easily be enhanced to track hiring operations in a human resources department. Hire uses the following event object to report recent hirings:

package hire;
import java.util.*;
public class HireEvent extends EventObject {
  private long hireDate;
  public HireEvent(Object source) {
    super(source);
    hireDate = System.currentTimeMillis();
  }
  public long getHireDate() {
    return hireDate;
  }
}

Interested targets (for example, manager objects for each department) must implement the appropriate interface and register for event notifications:

package hire;
import hire.*;
public interface HireListener
    extends java.util.EventListener {
  public abstract void hired(HireEvent e);
}

The Hire class manages targets with the vector hireListeners:

package hire;
...
public class Hire implements Serializable {
  ...
  private Vector hireListeners = new Vector();
  private PropertyChangeSupport changes =
    new PropertyChangeSupport(this);
  public Hire() {
  }
  public synchronized void
    addHireListener(HireListener l) {
      hireListeners.addElement(l);
  }
  public synchronized void
    removeHireListener(HireListener l) {
      hireListeners.removeElement(l);
  }

It issues hiring notifications with the method notifyHired():

  protected void notifyHired() {
    Vector l;
    HireEvent h = new HireEvent(this);
    synchronized(this) {
      l = (Vector)hireListeners.clone();
    }
    for (int i = 0; i < l.size(); i++) {
      HireListener hl =
        (HireListener)l.elementAt(i);
      hl.hired(h);
    }
  }

Hire supports the bound property salary:

  public void addPropertyChangeListener(
      PropertyChangeListener p) {
    changes.addPropertyChangeListener(p);
  }
  public void removePropertyChangeListener(
      PropertyChangeListener p) {
    changes.removePropertyChangeListener(p);
  }
  public void setSalary(float salary) {
    float old = this.salary;
    this.salary = salary; 
    changes.firePropertyChange("salary",
      new Float(old), new Float(salary));
  }
  public float getSalary() {
    return salary;
  }

At present, its bean-info class restricts the published properties to salary:

package hire;
import java.beans.*;
public class HireBeanInfo
    extends SimpleBeanInfo {
  public PropertyDescriptor[]
      getPropertyDescriptors() {
    try {
      PropertyDescriptor pd1 = new
        PropertyDescriptor("salary", Hire.class);
      pd1.setBound(true);
      return new PropertyDescriptor[] {pd1};
    } catch (Exception e) {
      return null;
    }
  }
}

With this base functionality, Hire provides a good starting point for customization, as illustrated in subsequent sections.

Custom Property Editors

As mentioned, IDEs provide property sheets for editing a Bean's configurable state. Property sheets vary from one IDE to another, but typically appear as a top-level dialog box.

The Beans Development Kit (BDK) provides a Bean testing tool, the BeanBox. Consider the BeanBox's property sheet for a Progress Bean with no bean-info class:

Note that several properties are inherited from the superclass.

Next, consider the Hire Bean:

HireBeanInfo restricts the displayed properties to whatever the developer feels is appropriate, in this case, a single property salary. These properties are commonly called published properties.

Next, suppose we would like to display a department property in the property-sheet dialog. Further, suppose that department is a discrete-valued property, so that we would like to present the range of values in a drop-down list for easy, error-free property updating:

To provide this functionality we must (1) implement the drop-down list as a custom property editor and (2) publish its existence with HireBeanInfo.

Task (1) involves several steps:

  • Extend the PropertyEditorSupport class
  • Implement the getValue() and setValue() methods
  • Implement the getAsText() and setAsText() methods
  • Implement the getTags() method for displaying values in a drop-down list

The JavaBeans framework provides a general-purpose mechanism for supplying custom property editors of specific designs. To use this mechanism, the developer who uses the JavaBeans architecture must implement certain prescribed methods, namely, those listed previously, and the framework handles the rest of the process. The getValue() and setValue() methods are invoked by the framework and provide a way to display and update values. The getAsText() and setAsText() methods map discrete values to user-friendly strings. Lastly, getTags() lists the strings (tags) for the drop-down list.

First, implement the methods for manipulating the property value, as displayed in the custom property editor:

import java.beans.*;
public class DepartmentEditor 
    extends PropertyEditorSupport {

  protected int dept;

  public void setValue(Object o) {
    dept = ((Integer)o).intValue();
    firePropertyChange();
  }

  public Object getValue() {
    return (new Integer(dept));
  }
  ...

Note that the dept instance variable is used within DepartmentEditor for local operations, and the name does not have to agree with the state variable for the department property in Hire. Note also that DepartmentEditor specializes PropertyEditorSupport, which provides functionality for broadcasting a property change; simply invoke the inherited firePropertyChange() method to signal an updated value.

How does the system work? The JavaBeans framework invokes setValue() and passes the data, namely, the current value of the property from the Hire instance, as an object. This value is stored locally, using whatever data type is appropriate. The framework invokes getValue() as necessary to display the property's value. The framework monitors updated values not by polling, but more efficiently, by registering itself for property change notifications, hence, the invocation of firePropertyChange(). Note that in this simple design you could have stored the intermediate integer value as an Integer object in lieu of the performing the complementary conversions back and forth to int.

Next, implement getAsText():

  public String getAsText() {
    switch (dept) {
      case Dept.MARKETING:
        return Dept.MARKETING_STR;
      case Dept.TRAINING:
        return Dept.TRAINING_STR;
      case Dept.SALES:
        return Dept.SALES_STR;
      case Dept.RESEARCH:
        return Dept.RESEARCH_STR;
      default:
        return Dept.UNASSIGNED_STR;
    }
  }
  ...

The framework uses this method to map string representations to the Bean's data type for internal representation of property values, in this case, int. (Dept is a public class that defines the constants. These values could be defined in a Dept interface, or within the Hire Bean itself.)

Next, implement setAsText(), which the framework uses for the complementary conversion:

  public void setAsText(String s) 
      throws IllegalArgumentException {
    if (s.equalsIgnoreCase(Dept.MARKETING_STR))
      dept = Dept.MARKETING;
    else if (s.equalsIgnoreCase(Dept.TRAINING_STR))
      dept = Dept.TRAINING;
    else if (s.equalsIgnoreCase(Dept.SALES_STR))
      dept = Dept.SALES;
    else if (s.equalsIgnoreCase(Dept.RESEARCH_STR))
      dept = Dept.RESEARCH;
    else
      dept = Dept.UNASSIGNED;
    firePropertyChange();
  }
  ...

Lastly, provide a getTags() method that delivers the tags for the drop-down list as an array of strings:

  public String[] getTags() {
    return new String[] {
      Dept.MARKETING_STR, Dept.TRAINING_STR,
      Dept.SALES_STR, Dept.RESEARCH_STR,
      Dept.UNASSIGNED_STR
    };
  }

Note that with this form of declarative specification for a custom property editor, the developer off-loads much of the work onto the JavaBeans framework. In many cases, this approach is considerably easier for the programmer than directly building the actual user interface for a property editor.

Next, you handle task (2), namely, publishing the property editor via the bean-info class. The updated HireBeanInfo follows:

public class HireBeanInfo extends SimpleBeanInfo {
 public PropertyDescriptor[] 
   getPropertyDescriptors() {
  try {
   PropertyDescriptor pd1 = new
    PropertyDescriptor("salary", Hire.class);
   PropertyDescriptor pd2 = new
    PropertyDescriptor("department", Hire.class);
   pd2.setPropertyEditorClass(
    DepartmentEditor.class);
   return new PropertyDescriptor[] {pd1, pd2};
  } catch (Exception e) { return null; }
 }
}

Thus, when an IDE's Bean analyzer requests the array of published properties, it queries each PropertyDescriptor instance for the associated property editor, if any.

Magercise

  1. The StickFigure Bean with a Custom Property Editor

Customization Dialogs

Sometimes the developer who uses the JavaBeans architecture simply needs total freedom to design a property editor for one or more, possibly specialized, properties. In this case, the JavaBeans framework allows the developer to design and register a custom, graphical object—typically, as a collection of GUI components in a container (panel). Most IDE's display the panel inside a dialog box. In some IDEs, the dialog is modal; in others, it resides on the desktop as a top-level window.

This customizer implementation is free to use any of the classes provided by the JavaBeans framework, for example, PropertyEditor. The customizer must specialize java.awt.Component and implement java.beans.Customizer. A Bean analyzer uses the BeanInfo-prescribed method getCustomizerClass() to retrieve the customizer.

The BDK ships with several sample JavaBeans, including ExplicitButton and ExplicitButtonCustomizer:

In this section, you'll implement a customizer for the Hire Bean. A customizer can do anything really; it is not limited to setting property values. For the Hire Bean, however, the customizer simply provides GUI components for configuring two properties:

  • salary: using a TextField object
  • department: using a Choice object

The following outline summarizes the complete process. The customizer must:

  • Publish itself via the bean-info class (HireBeanInfo)
  • Implement the Customizer interface:
    • addPropertyChangeListener()
    • removePropertyChangeListener()
    • setObject()
  • Provide a no-argument constructor:
    • IDEs will use newInstance() to instantiate the customizer
  • Subclass Component:
    • IDEs will instantiate the customizer inside a dialog window

First, HireBeanInfo must specify the customizer by implementing getBeanDescriptor():

public class HireBeanInfo
    extends SimpleBeanInfo {
  public BeanDescriptor getBeanDescriptor() {
    return new BeanDescriptor(
      Hire.class, HireCustomizer.class);
  }
  ...

Next, HireCustomizer implements ActionListener, to respond to the <Enter> key in the text field for salary, and implements ItemListener, to respond to selections in the Choice instance for dept:

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
public class HireCustomizer extends Panel
    implements Customizer, ActionListener,
    ItemListener {
  private Hire hireObject;
  private TextField salary;
  private Choice dept;
  private PropertyChangeSupport support;
  ...

Next, a no-argument constructor supports dynamic instantiation:

  public HireCustomizer() {
    support = new PropertyChangeSupport(this);
    ...

For simplicity, implement the user interface directly in the constructor. First, create the dialog contents for salary:

  public HireCustomizer() {
    ...
    setLayout(new GridLayout(2, 1));
    Panel p1 = new Panel();
    p1.setLayout(new BorderLayout());
    add(p1);
    p1.add(new Label("Salary:"), BorderLayout.WEST);
    p1.add(salary = new TextField(20),
      BorderLayout.EAST);
    salary.addActionListener(this);
    ...

Next, build the dialog contents for dept:

  public HireCustomizer() {
    ...
    Panel p2 = new Panel();
    p2.setLayout(new BorderLayout());
    add(p2);
    p2.add(new Label("Department:"),
      BorderLayout.WEST);
    p2.add(dept = new Choice(), BorderLayout.EAST);
    dept.addItemListener(this);
    dept.add(Dept.MARKETING_STR);
    dept.add(Dept.TRAINING_STR);
    dept.add(Dept.SALES_STR);
    dept.add(Dept.RESEARCH_STR);
    dept.add(Dept.UNASSIGNED_STR);
  }
  ...

You must provide the method setObject() to capture the reference to the Hire Bean instance:

  public void setObject(Object obj) {
    hireObject = (Hire) obj;
    salary.setText(
      String.valueOf(hireObject.getSalary()));
    selectChoiceItem();
  }

  private void selectChoiceItem() {
   if (hireObject.getDepartment() == Dept.MARKETING)
    dept.select(Dept.MARKETING_STR);
   else if (hireObject.getDepartment() == Dept.TRAINING)
    dept.select(Dept.TRAINING_STR);
   else if (hireObject.getDepartment() == Dept.SALES)
    dept.select(Dept.SALES_STR);
   else if (hireObject.getDepartment() == Dept.RESEARCH)
    dept.select(Dept.RESEARCH_STR);
   else
    dept.select(Dept.UNASSIGNED_STR);
  }
  ...

Note that you cannot assume that the Hire Bean is instantiated prior to its customizer. Whenever setObject() is invoked, you'll need to receive and store the associated Hire object reference using the instance variable hireObject. At this time, you can initialize the GUI components for each property by querying the Hire instance.

The customizer must respond to action events for the salary property's text field:

  public void actionPerformed(ActionEvent e) {
    Object source = e.getSource();
    if (source == salary) {
      String text = salary.getText();
      try {
        hireObject.setSalary(
          (new Float(text)).floatValue());
      } catch (NumberFormatException ex) {
        salary.setText(String.valueOf(
          hireObject.getSalary()));
      }
      support.firePropertyChange(
        "salary", null, null);
    }
  }
  ...

Also, it must respond to selections for the department property's Choice object:

  public void itemStateChanged(ItemEvent e) {
   Choice c = (Choice) e.getSource();
   String label = (String) c.getSelectedObjects()[0];
   if (label == null)
    return;
   if (label.equalsIgnoreCase(Dept.MARKETING_STR))
    hireObject.setDepartment(Dept.MARKETING);
   else if (label.equalsIgnoreCase(Dept.TRAINING_STR))
    hireObject.setDepartment(Dept.TRAINING);
   else if (label.equalsIgnoreCase(Dept.SALES_STR))
    hireObject.setDepartment(Dept.SALES);
   else if (label.equalsIgnoreCase(Dept.RESEARCH_STR))
    hireObject.setDepartment(Dept.RESEARCH);
   else
    hireObject.setDepartment(Dept.UNASSIGNED);
   support.firePropertyChange("department", null, null);
  }
  ...

Lastly, the customizer must support other objects that listen for property changes:

  public void addPropertyChangeListener(
      PropertyChangeListener l) {
    support.addPropertyChangeListener(l);
  }

  public void removePropertyChangeListener(
      PropertyChangeListener l) {
    support.removePropertyChangeListener(l);
  }
}

The IDE, for example, can register an interest in property changes, depending on its design.

Typically, customizers are popped up from a command button or a menu. In the BeanBox, for example, customizers are available from a menu:

With some IDEs, for example, SuperCede, customizers have a command button in the property sheet.

Magercises

  1. The StickFigure Bean with a Customizer Dialog
  2. Exploring Bean Customization: FlexLabel

Software Components with JavaBeans

The JavaBeans API discussion began with a reminder that M. D. McIlroy (1968) made a plea for catalogs of software components more than 30 years ago. JavaBeans, of course, is the standard component architecture for Java technology.

JavaBeans is particularly well-suited for asynchronous, intra-application communications among software entities. That is, JavaBeans is an intra-JVM (Java1 Virtual Machine) framework. Every target, for example, that registers with a source does so by handing over its object reference, which the source Bean typically maintains internally in a vector. This framework does not allow (in any direct way) for inter-application source-target communication because object references are local to the JVM that houses the running application.

There are several component technologies in the distributed computing arena. Currently, the CORBA-based frameworks are the most popular, but newer component technologies such as Enterprise JavaBeans and mobile agents, for example, Aglets, show considerable promise as well.

The JavaBeans technology has been enhanced in some environments to support location transparency (almost). For example, the Java application server from WebLogic/BEA Systems includes a JavaBeans implementation wherein each Bean is (in effect) wrapped in a network layer. Thus, the source Bean could be running in the application server and the target object could be running on a distant client.

It's clear that there is now, finally, a strong movement toward component-oriented design and implementation. Some enterprises dictate, for example, that every Java class be designed and implemented as a JavaBeans component. In these enterprises, programming groups exchange and share their software developments as Beans—they use each other's work in a plug-and-play application development setting.

There is, of course, some additional overhead in designing classes as Beans. In some environments (IDEs), you must provide void, no-argument methods to connect Beans together graphically in lieu of traditional source code-level method invocation in which the method signature has no limits. Several IDEs, however, support Bean-connecting operations for methods that have arguments and return data.

The fundamental Bean requirement of a no-argument constructor implies that some programmers must change their design habits. In general, it's a bad idea to use constructors for extensive class configuration during instantiation. At first, it may seem like a good idea to provide 20 or 30 constructors for an everything-but-the-kitchen-sink class implementation—one for every possible combination of relevant configuration options. Classes with many, complex constructors, however, almost always lead to "documentation-itis" during development and result in unreadable source code once the application moves to the maintenance phase.

The (practical) research on software design has suggested for more than ten years that certain object-oriented programming styles are effective, and, at a somewhat more abstract level, certain design patterns tend to reappear with incredible regularity in most properly designed (large) applications. These design pattern are summarized and cataloged in Design Patterns, by Gamma, et al. (1994).

In the 1980s there was a movement, for a time, toward declarative programming languages, for example, Prolog. A declarative versus procedural language debate is beyond the scope of this discussion, but even procedural programming bigots generally accept that declarative languages have merits, and most (not all) procedural languages include declarative features, for example, variable declarations.

A fundamental characteristic of declarative languages is that they allow programmers to, in a sense, describe the state of an application, whereupon the application adapts to that description, as opposed to requiring that programmers intricately manipulate (execute) an application to arrive at a certain state.

It's clear that the JavaBeans framework has a declarative flavor and facilitates component design that involves plug-and-play, descriptive, declarative assembly of an application from cataloged parts. That is, you build applications by plugging and hooking together smaller components, each of which takes on the responsibility of adapting itself to the declarative specifications that appear in an IDE's property sheet, or customization dialog.

The previous Magercises demonstrate the principal issues that arise in using the JavaBeans framework. This section concludes with several Magercises that reinforce the idea that you can (and probably should) design most classes, even nongraphical classes, as Beans. For most programmers, "designing with Beans" is simply a commitment to creating classes with reasonable default values and methods that rigorously adhere to the "test-its-value-before-using-it" principal.

For these somewhat larger Magercises your solution will surely differ from the ones included here. The important issue, however, is that you provide a workable mechanism for inter-component communication. With modern operating and windowing systems, this approach implies a concerted effort to design all components to adhere to and work well within an event-driven, asynchronous paradigm.

Magercises

  1. A Client Socket Bean
  2. A URL Hex Dump Bean
  3. A JDBC Bean Database Manager
  4. Exploring an HTML Browser Bean

Further Information

Further web-resident information on JavaBeans is available from:

Component technologies are prevalent in the distributed computing arena. Recent books with distributed computing themes and coverage of component technologies include:

  • Farley, J. Java Distributed Computing. Sebastopol, CA: O'Reilly & Associates, 1998, ISBN: 1-56592-206-9.
  • Lange, D. B. and Oshima, M. Programming and Deploying Java Mobile Agents with Aglets. Reading, MA: Addison-Wesley, 1998, ISBN: 0-201-32582-9.
  • Orfali, R. and Harkey, D. Client/Server Programming with Java and CORBA, 2nd Ed. New York: John Wiley & Sons, 1998, ISBN: 0-471-24578-X.

The home for the ICE Browser Bean is ICEsoft.

The suppliers and parts data is based on similar data from Chris Date's classic database text:

  • Date, C. An Introduction to Database Systems, 6th Ed. Reading, MA: Addison-Wesley, 1994, ISBN: 0-201-54329-X.

Recent books on JavaBeans and related topics include:

  • Englander, R. Developing JavaBeans. Sebastopol, CA: O'Reilly & Associates, 1997, ISBN: 1-56592-289-1.
  • Gamma, E., Helm, R., Johnson, R., Vlissides, J. Design Patterns: Elements of Reusable Object-Oriented Software. Reading, MA: Addison-Wesley, 1994, ISBN: 0-201-63361-2.
  • Rodrigues, L. H. The Awesome Power of JavaBeans. Greenwich, CT: Manning, 1998, ISBN: 1-884777-56-2.

Historical references for object-oriented and component-based programming include:

  • Cox, B. R. Object-oriented programming: An Evolutionary Approach. Reading, MA: Addison-Wesley, 1986, ISBN: 0-201-10393-1.
  • McIlroy, M. D. Mass-produced Software Components. In Software Engineering Concepts and Techniques (republication of materials from the 1968 NATO conference on software engineering, eds. Buxton, J. M., Naur, P., and Randell, B.). New York: Petrocelli/Charter, 1976, ISBN: 0-884-05334-2.

_______
1 As used on this web site, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

Copyright © 1998-1999 MageLang Institute. All Rights Reserved.


Print Button
[ This page was updated: 21-Sep-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary | Feedback | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.