Bean Markup Language, Part 2

Create event-driven applications with BML

Any system made up of components needs a way to connect those components to one another. In an automobile, that framework is the auto frame (itself a component), to which other components are attached. In electronics, it's the chassis, the circuit board, or the substrate, depending on what level of component-use you mean.

Last month, a reader commented that BML didn't work as well as an IDE, or integrated development environment, for creating user interfaces, and I agree. But the power of and interest in BML derives from its ability to create structures of arbitrary classes -- not just user interfaces or JavaBeans -- to build an application. More importantly, BML can define an application declaratively, usually without procedural code. This makes it much easier for (potential) builder tools to compose functionality into applications, much in the same way a dialog editor composes GUI elements into a user interface. In fact, since BML defines applications structurally rather than procedurally, it can be used to automatically generate interactive interfaces for arbitrary datastructures.

IBM's Bean Markup Language provides just such a software chassis for Java object instances, particularly instances of JavaBean components. As I demonstrated in August (see Part 1 of this two-part series in Resources below), you can use BML to create configured instances of JavaBeans.

This month, I'll show you how to create instances of several objects in BML and then use BML to wire these objects together. I'll also show you how to execute any method of an object from BML, extend BML to handle conversions between data types, and explore binding Java objects created in BML to a scripting language (in this case, JavaScript). Since I assume you've read the first article, let's dive right into this month's sample code.

A BML application

I'm going to extend last month's ColorFadeBean by transforming it into the interactive ColorFadeEditor.bml (click the link to see the file). I've added an AWT text field to the original ColorFadeBean, which sets the text in the ColorFadeBean, and three ColorChooser objects, which set the text color and the start and end colors for the color gradient. A picture of the ColorFadeEditor appears in Figure 1.

Figure 1. ColorFadeEditor defined entirely in BML

This application is actually a single-nested hierarchy of GUI elements, as it must be, since an XML document may have only one top-level element. You'll notice that the BML file contains no Java code. That's because BML is a language used for wiring JavaBeans together, not for creating new JavaBeans (although defining JavaBeans in BML will be a feature of an upcoming BML release). The color gradient in the ColorFadeBean, for example, is created by the bytecodes in ColorFadeBean.class, which can be considered an off-the-shelf JavaBean. BML sets the bean's exposed properties and so on, but it can't add new properties or behavior.

The top-level object in the object tree is a java.awt.Frame, containing a panel above (to hold the TextField for editing the message text), a panel below (holding the color editors), and a ColorFadeBean (which we're editing) in the middle. The structure of the entire document appears in Figure 2.

 
Frame MainFrame
  • BorderLayout
  • Font LabelFont
  • ColorFadeBean FadeBar
  • Panel
    • GridLayout
    • Label
    • ColorChooser TextColorEditor
    • Label
    • ColorChooser FromColorEditor
    • Label
    • ColorChooser ToColorEditor
  • Panel
    • BorderLayout
    • TextField TextEditor
 
Figure 2. The structure of ColorFadeEditor.bml

In Figure 2, the class name of each nested object appears with its optional symbolic id in italics. Giving an object a symbolic id in a BML file allows that object to be looked up and used elsewhere in the script. (An example is given below in our next section.)

When this BML script is running, changing the colors or the text in the window immediately changes the properties of the ColorFadeBean. Note that this entire application was written in BML: no Java code was necessary beyond what already existed in the class files used to implement it. In fact, with just a little more work, you could use this editor as the customizer (as in java.beans.Customizer) for the ColorFadeBean class.

The ColorChooser objects you see in the application are a custom color editor I wrote as a support class for this article. These objects could have been defined as in-line BML, but creating a new JavaBean (ColorChooser) and wiring it into the application better demonstrates BML as a wiring language and makes the sample code shorter.

You'll notice that, when the ColorFadeEditor window appears, the color editors and the text editor are already initialized to the corresponding color and text values in the ColorFadeBean. And how was the font for the color editor labels set? These widgets got these initial values by way of the <property> tag, which you can use not only to set property values but also to look them up.

A question of values

In Part 1, I used the <property> tag to set the value of a property. You can use <property>, like many other BML tags, to look up values as well as set or create them. For example, look at how the TextField item at the top of the application receives a value of "Emeralds and Sapphires." The entire add operation that adds the text field appears in Listing 1.

Line 140 declares that whatever it contains should be added to the enclosing container (in this case, a java.awt.Panel). Line 141 creates java.awt.TextField and gives it the name TextEditor. Any bean can name itself upon creation by setting its id attribute. id registers the bean with the BML object registry, a table inside the BML processor. Later, BML code will be able to access this bean by name, as you're about to see.

Line 142 defines an argument to the TextField's constructor. The <string> tag creates a string, <cast> casts the string to an int, and <args> indicates to the enclosing <bean> tag the arguments to use for the constructor. Since the <args> tag contains a single integer (with a value of 80), the BML processor selects java.awt.TextField(int) as the constructor to use to create the text field.

Lines 143 through 145 set the TextField's text property to the value of ColorFadeBean's message property. Instead of using the <property name="..." value="..."/> syntax from Part 1, line 143 declares the property to be set, but the value is retrieved from that tag's contents.

The <property> tag's target attribute looks up the ColorFadeBean by its id (the string FadeBar) in the BML object registry, and then the value attribute selects the value to retrieve. The ColorFadeBean has the id FadeBar because it registered with the object registry under that name when it was created on line 29, shown in Listing 2:

 
029     <bean class="com.javaworld.JavaBeans.Oct99.ColorFadeBean " id="FadeBar">

Listing 2. Create a ColorFadeBean and assign it a name

The structure you see in lines 143 through 145 is equivalent to an assignment statement; it assigns the property value of one bean to another bean. Note that this assignment doesn't create a permanent link between the two properties; that is, the properties aren't bound together after this assignment. It simply assigns the TextField value at the time the field is created.

What if you wanted to bind properties together? Since the application is an editor, you want any change in the value of the ColorChooser to change the corresponding property in the ColorFadeBean (messageColor, fromColor, or toColor). In Java code, objects typically talk to each other using events. BML provides that capability in the form of event-bindings, which I'll discuss next.

Wiring beans together

Creating a running instance of a Java class, as you've seen so far, is a cool trick. It's pretty useless, though, without a way to use that object. The standard Java event model, introduced in JDK 1.1, provides a way for Java objects to communicate with one another by sending events, objects that encapsulate some sort of occurrence. (If you need to brush up on the Java event model, see my JavaWorld article, "Keep listening for upcoming events," in Resources.)

The <event-binding> BML tag establishes an event listener relationship between a target bean (the bean that produces the event) and some action performed when that event occurs.

When you're writing event code by hand, you'll typically set up an event relationship this way:

    eventSource.addEventtypeListener(eventReceiver);

This line of code means "notify the eventReceiver object whenever the eventSource object has an eventType event."

An example would be

 window.addWindowListener(windowEventProcessor); 

which means "notify the windowEventProcessor anytime the window has a windowEvent."

BML takes a slightly different approach. Instead of binding objects directly together, BML makes one bean listen for events on another bean: it binds event sources to scripts, which are chunks of code (in either BML or some other scripting language) defined by the BML <script> tag. An adapter object is the event listener, which listens for events on its event source and executes its script whenever the event occurs. An adapter object is created for each event-binding in a BML script.

The <event-binding> tag binds a BML script to a particular event type on a particular bean. Its syntax is as follows:

    <event-binding [target="id"] name="eventtype">

The optional target attribute defines which object is the source of the event. It's a little confusing that the event source is identified by a tag called target, but that's because target is the BML attribute that any tag uses to look up a bean -- target was probably a poor name choice for that attribute. The target attribute is optional because the default target for an event-binding is the <bean> tag in which the binding is enclosed.

In the sample code, I've chosen to locate all event-bindings at the bottom of the script, but I could have placed them anywhere. Listing 3 shows the event-binding in the example that updates the FadeBar's fromColor property in response to a change in the fromColorEditor's value.

In summary, the code above means:

  • When the FromColorEditor has a PropertyChangeEvent (line 205), execute the following <script> (line 206):
    • Set the colorFrom property of the object called FadeBar (line 207) to:
      • the result of typecasting to java.awt.Color (line 208)
        • the result of calling the FromColorEditor's getValue() method (line 209)
    • Call the FadeBar's repaint() method
    • (line 212)

When the PropertyChangeEvent in the object with id FromColorEditor fires, the adapter object listening for this event is notified, and the BML script attached to the adapter is executed. The FadeBar object's fromColor property is then updated.

That mechanism works for any event type. Values from the event object itself can be accessed by the script. See the details in the tutorial and reference manual that come with the BML package.

Calling methods

I've used a tag in the example above, <call-method>, that you haven't seen before. The <call-method> tag calls an arbitrary object or class method. The tag uses the target attribute to indicate the object or class upon which the method is to be invoked. The example in Listing 3 shows a call to the FadeBar object's repaint() method. You can also call static methods within classes, by using the class: modifier inside the target attribute's value. The example in Listing 4 shows how to do this.

Related:
1 2 3 Page 1
Page 1 of 3