BML Tutorial for JavaBeans Configuration
BML Tutorial for JavaBeans Configuration
(Version 2.3)
Tutorial
Joseph Kesselman and Matthew J. Duftler
IBM TJ Watson Research Center
Hawthorne, NY 10532.
[Link]
[Link]
ABSTRACT
Bean Markup Language (BML) is an instance of an XML-based component configuration or wiring
language customized for the JavaBean component model. The language is designed to be directly
executable; i.e., processing a BML script will result in a running application configured as
described in the script. The BML language has elements that can be used to describe the creation
of new beans, accessing of existing beans, configuration of beans by setting/getting their
properties and/or fields, binding of events from beans to other beans, as well as calling arbitrary
methods in beans.
We provide two implementations of BML - a player which interprets a BML script to produce a
running bean and a compiler which translates a BML script to Java. The player is implemented
using Java reflection and is very small (approximately a 35K jar file). The compiler produces
reflection-free Java code similar to the code one would write by hand to implement the same
component structure described in the BML script it is compiling. The advantage of using BML and
the compiler to generate the Java code vs. writing the code directly is that the machine generable
BML language captures in a first-class form the inter-component structure of the application which
can then be compiled away to avoid any run-time performance loss.
This document is a beginner’s tutorial for BML. It is intended to be read in conjunction with the
BML User’s Guide.
Table of Contents
1. INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2. JUGGLER1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1 BML CODE AND EXPLANATION ........................................... 3
2.2 PLAYING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 COMPILING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3. JUGGLER2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.1 BML CODE AND EXPLANATION ........................................... 8
3.2 PLAYING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.3 COMPILING . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4. EVOLVING JUGGLER1 TO JUGGLER2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.1 BASIC JUGGLER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.2 ADDING THE SPEED CONTROL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.3 ADDING THE TEXT FIELD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.4 MAKING THE TEXT FIELD EDITABLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5. CALCULATOR WITH JAVASCRIPT LOGIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6. APPENDICES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.1 APPENDIX A: [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6.2 APPENDIX B: [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.3 APPENDIX C: INCREMENTAL BML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.4 APPENDIX D: CALC_JS.BML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1. INTRODUCTION
BML is an XML language for describing the structure of a set of interconnected beans. It is not an XMLized Java
syntax - it can only be used to describe how a set of beans are to be created, configured and interconnected. It is in
many ways a new kind of language - it is not a Turing-complete programming language neither is it a full scripting
language; it is a language whose only functions are to describe how components relate to one another and how each
of those components is configured. It is however, not a modeling language - it is directly executable.
2. JUGGLER1
This is a BML instantiation of the "Juggler" demonstration of JavaBeans. It assembles a simple application based on
a few AWT components (Panel, LayoutManager, and Button), plus a Juggler animation bean based on one of the
standard Swing demos. Although this application is built entirely from user-interface beans, the same principles
would apply to constructing and connecting "back-end" beans.
One piece of advice before we begin: Properly indenting the BML, or using an XML editor which will display the
document's hierarchy, can make reading and maintaining the code considerably easier.
<?xml version="1.0"?>
Now we can start writing BML. We begin by creating the Frame which will contain our user interface. We will include
an id attribute, with the value “topFrame”, in case we want to retrieve this bean later.
The following is an example of setting a bean's property with a literal value string. The [Link]()
method expects an Color as its parameter, so BML will automatically look in its Type Converter Registry to find a
String-to-Color converter (which is one of the standard converters supplied with BML) and use that to obtain a
suitable Color object. Note that we don't have to specify a target bean; since we're within the context of the Frame’s
<bean> element, that's the default target.
Next we set a layout manager on this Frame, to control where the beans will be placed within it. Since there is no
String-to-Layout Manager converter, we use a <bean/> element to construct and return a bean of the proper type,
and make that the child of (and hence an argument to) the <property> element. Since [Link]() expects a
LayoutManager as its argument, and BorderLayout is a subclass of LayoutManager, BML doesn't have to do any
type conversion.
<property name="layout">
<bean class="[Link]"/>
</property>
Now that we have the Frame ready to use, we can start placing the user-interface beans within it. We could do this by
explicitly calling the panel's add() method. But the <add> element, which abstracts the concept of adding beans to a
collection, is a bit easier to work with and easier to read, so let's use that. Since we're still within the Frame <bean>'s
context, the Frame is our default target bean for the add operation.
<add>
The first bean we want to place inside this Frame is the Juggler animation itself. Since we'll want to connect other
beans to it later, we'll register it with the BML Object Registry by assigning it the ID string "Juggler".
While we've got this bean open, let's configure it. We could do so later, of course, by referring to it via its ID, but it's
often convenient to initialize a bean at the time that it is created.
To initialize the juggler's animationRate property, we'll use a literal string. [Link]() expects an int
as its parameter, so BML will look up and apply the appropriate type conversion.
We'd like the Juggler animation to be running when the application starts. Unfortunately, Juggler is not entirely
beanified; rather than having a "running" property with a setRunning() method, the Juggler wants us to call the
object's start() or stop() methods. Since BML allows you to access specific methods as well as properties, you aren't
limited to the "well-designed bean" interfaces.
<call-method name="start"/>
We don't have any other changes we want to make to the Juggler bean right now, so we close its context.
</bean>
That returns the Juggler bean to the <add> element. Since we're using BorderLayout in this Frame, we'll also need to
specify the border position (North, South, East, West, or Center) we want this bean to occupy within the Frame. Let's
put the Juggler in the center of the Frame, by supplying the string "Center" as the second parameter of the <add>.
<string value=”Center”/>
We now close the <add> element. BML will use its Adder Registry to find an Adder that knows how to add to a
Frame, and invoke that adder; the Juggler and the String will be passed as arguments to the Adder.
</add>
To finish the Juggler1 demonstration, we'd like to add a pair of buttons at the top of the Frame that will stop and
restart the animation. We could perform these operations in various orders, but it's convenient to take advantage of
the containment hierarchy and map that to the structure of the BML. So we'll start by adding a Panel within the
Frame, accepting its default layout manager.
<add>
<bean class="[Link]">
Within that panel, we create and add the "Start" button, and set its label property appropriately.
<add>
<bean class="[Link]">
<property name="label" value="Start"/>
We want this button to start (or restart) the Juggler bean's animation when it is pressed. If the Juggler had a suitable
event-listener method, all we would have to do is tell BML which source bean would generate the event, which event
(and, if appropriate, sub-event) we wanted to respond to, and which target bean we wanted to route the event to. But
the Juggler API, as Sun’s demo defined it, doesn't have an appropriate event listener for starting and stopping
animation... or even a “running” property. Instead, we need to wire up the event to produce an explicit method call to
start or stop animation.
To achieve this behavior in hand-coded Java, you would build an adapter bean which listens for the event and
invokes the Juggler bean's start() method. In BML, we use a <script> block which describes a sequence of operations
to be performed when the event is fired. Scripts can extract parameters from the event, if required. In this case,
[Link]() doesn't take any parameters, so all the adapter needs to do is invoke the start() method.
Note that the event’s source bean, as always, defaults to the <bean> enclosing the <event-binding> -- which in this
case means the Button.
<event-binding name="action">
<script>
Now for the scripted action: when we get the event, start() the Juggler’s animation:
Since that’s all we want to do, we can now close the script and event binding.
</script>
</event-binding>
That completes our Button bean. And since the default layout manager doesn't need a second parameter, we can end
the <add> too.
</bean>
</add>
The "Stop" button is almost identical to the "Start" button we've just discussed. The only changes are its name, and
the method that gets called in response to the event.
<add>
<bean class="[Link]">
<property name="label" value="Stop"/>
<event-binding name="action">
<script>
<call-method target="Juggler" name="stop"/>
</script>
</event-binding>
</bean>
</add>
That completes the contents of the panel. We can now close it, which returns it as the first parameter of the <add>
that encloses it. Since the layout of the Frame is managed by a BorderLayout, the <add> requires a second argument
to specify the position -- in this case, "North".
</bean>
<string value=”North”/>
</add>
And that completes our design of the demonstration; after we close the Frame, it'll be ready to run.
</bean>
Appendix A shows what [Link] looks like when we put it all together. The Juggler1 demo can also be found in
the demos/juggler directory.
2.2 PLAYING
The easiest way to test BML is to run the BML Player. For embedability, the BMLPlayer class reads a Document
Object Model (DOM) representation of the BML and interprets the BML commands found therein. Therefore, to use
the player, we must first parse the BML into a DOM tree. To display the resulting bean, we need some additional
code. PlayerDriver is a Java program that provides these additional functions:
Ÿ The driver starts by using an XML parser, such as IBM's XML4J, to read the BML source code and build a
DOM tree. (See section 4.6 in the BML User’s Guide for information on how to use a different parser.)
Ÿ Next, the driver hands that DOM to the BMLPlayer, which processes it and returns the outermost bean to the
driver.
Ÿ Then, the driver determines whether it was run as an application or as an Applet. If it's an application, it checks
whether the returned Bean is an instance of Frame, and either displays that Frame, or, if necessary, wraps a
Frame around the BML-generated Bean and displays that. If it is running as an Applet, the driver either displays
the bean within itself (the PlayerDriver), or, if the bean is a Frame, displays that Frame.
Ÿ Finally, the driver registers itself as a Window Listener so it can shut itself down cleanly if the user closes the
Frame's window.
If you write your own driver, it can do other things as well. For example, you might want to provide special Adapters
or Type Converters to meet the needs of your BML application. Or, you might want to make some beans available to
your BML code. The driver can add these classes and objects to the appropriate registries before running the Player.
When the Juggler starts up, the “Bee” will start juggling the “Eye”, the “Bee”, and the “M”. Pressing the Stop button
will stop the animation. Pressing Start will start it again. As you can see, we've gotten exactly the beans and event
wiring that we described in the BML.
KNOWN QUIRK: The Juggler application may unpredictably stop for a few seconds. and then restart again. As far as
we can tell, that's due to Java having to take time out periodically to run garbage-collection.
2.3 COMPILING
In many situations it may not be necessary to interpret BML while your application is running, but you may still want
to use BML to generate your bean configuration code. In this case, you would use the BML Compiler, which
generates reflection-free Java code rather than returning the running beans. This Java can then be compiled and run
as a stand-alone application, or embedded in a larger application, just like any other Java class.
The BML Compiler, like the BML Player, is designed to read its input from a DOM tree. BML comes with a driver for
the Compiler, much like the PlayerDriver, which can be invoked from the command line to parse a BML file and then
invoke the Compiler. As with the Player, the CompilerDriver may also pre-load classes and beans into the various
Registries to make them available during BML compilation.
To compile the Juggler1 demo into Java code, using the CompilerDriver:
Ÿ Compile CompilerDriver if necessary (it's in the demos/driver directory).
Ÿ Compile the [Link] bean:
javac [Link]
Ÿ Set your classpath so that it includes the BML directory, [Link] and the XML parser xml4j_X_Y_Z.jar (where
X, Y and Z match the file in the lib directory).
Ÿ Issue the command
java [Link] -in [Link] -out Juggler1Demo
-in specifies the BML file (or URL) you want to process, in this case [Link]. If not specified,
the CompilerDriver will read from the Standard Input stream.
-out specifies the fully-qualified class name of the .java file to be produced; in this case
“Juggler1Demo”. The compiler will also determine the package name from the given argument, and
generate an appropriate package statement at the top of the generated Java code. If this option isn't
specified, the CompilerDriver defaults to producing a class named “Test”, in the unnamed package.
Note: If you accidentally specify the name of an existing java file (such as Juggler), the
CompilerDriver will write over it without warning
-method specifies the method name in the generated Java code which will perform the bean
configuration operations specified by the BML. Default is "exec".
-save determines whether the generated Java code will be written to an output file. If turned off, the
generated Java is written to the Standard Output stream. Note that the program which invoked the
compiler can capture this stream for further processing; BML’s “applettool” driver uses this
technique to display the Java code on the screen. Default is on.
-format determines whether the generated Java code should be formatted. This includes things
such as indenting and word-wrapping. Turning this off makes the code less readable, but saves
some storage and some processing time. Default is on.
-verbose determines whether status messages will be displayed during compilation. Error messages
will always be displayed. Default is on.
-javac, when turned on, causes the generated Java code to immediately be compiled. This is a
convenient feature if you want to go direct from BML to a runnable class file. It requires that a
copy of the JDK be installed and that the paths be set properly to find it. Default is off.
-dynamic has the same effect that it did in the player: allows event adapter classes to be generated
"on demand" rather than being limited to those pre-loaded into the Event Adapter Registry. Default
is off.
-bmldep turns on/off dependency of generated Java code on BML run-time. Default is on.
With the command-line arguments we passed, the CompilerDriver will load the BML file, process it, and produce a
.java file containing the Juggler1Demo class. This class will have an exec() method that performs the bean
configuration tasks specified by the BML file, and an application main() method that invokes
[Link]() to create a Frame, if necessary, and display the results of the exec() invocation
within it.
The generated [Link] can now be compiled and run. The application should start up faster than it did
when run via the PlayerDriver, since the BML interpreter no longer runs.
Note that the class files add up to roughly four times as many bytes as the BML source, which suggests that there
may be times when downloading an applet as BML and processing it locally may be faster than pre-compiling it and
downloading the class files. The run-time performance of the application should be the same either way.
3. JUGGLER2
Now let's try a slightly enhanced version of the Juggler1 demo, which adds an animation speed control slider and a
field that contains the current value of that parameter.
<?xml version="1.0"?>
<bean class="[Link]" id=”topFrame”>
<property name="title" value="IBM Juggler"/>
<property name="background" value="0xeeeeee"/>
<property name="layout">
<bean class="[Link]"/>
</property>
<!-- Add the Juggler bean (see above) -->
<!-- Add the start/stop Panel (see above) -->
At this point, the original [Link] just closed the Frame bean. But we want to add a few more beans before we do
so.
We begin by creating the Scrollbar and adding it to the Frame. We need to set its minimum and maximum properties
to a range that is useful for the animation speed, in this case from 0 (no delay, maximum speed) to 220.
<add>
<bean class="[Link]" id="scale">
<property name="minimum" value="0"/>
<property name="maximum" value="220"/>
It might be confusing if the slider's initial setting is different from the Juggler's initial animation rate. We could
initialize it to the same literal value (110) that we used to initialize the Juggler, but that's risky; if we decide we want to
change the Juggler's starting speed, we'd have to remember to update this as well. A better solution is to ask the
Juggler for a bean representing the current value of its animationRate property, and use that to initialize the
Scrollbar's value property.
<property name="value">
<property name="animationRate" target="Juggler"/>
</property>
Now we bind the Scrollbar's adjustment events -- which indicate that its slider has been moved by the user -- to the
Juggler. When the event is fired, we want to set a new delay value for the Juggler’s animationRate property:
<event-binding name="adjustment">
<script>
<property target="Juggler" name="animationRate">
But what should it be set to? To find out, we need to look inside the AdjustmentEvent and retrieve its “value”
property. When an event is connected to a <script> block, BML automatically assigns positional names (event:arg0,
event:arg1, ..., event:argn) to the arguments of the generated event adapter’s listener method.
Note: event:arg0 is the filter. In most cases, event:arg0 will be a String representing the name of the method via which
the event was delivered (e.g. “actionPerformed”). However, if the name of the event is propertyChange or
vetoableChange, then event:arg0 will be a string representing the name of the property.
An AdjustmentListener expects one argument, the event itself, so the event object will temporarily be given the name
event:arg1 (event:arg0 equals “adjustmentValueChanged”, the name of the method). We can use this name to retrieve
the AdjustmentEvent, and use the “get property” syntax to find out what value the user requested. This value will be
passed up to the enclosing set-property, and be set into the Juggler’s animationRate.
That's all we need to do to the Scrollbar, except for closing it and finishing the <add> by putting it at the East (right)
edge of the Frame’s BorderLayout.
</bean>
<string value=”East”/>
</add>
The Scrollbar is a good control and qualitative display, but it would be nice to know exactly what the Juggler’s
current delay between frames is. We should probably label that display, so people know what it means. The simplest
way to do this is via the same technique we used for our Start and Stop buttons: create a Panel with the default
layout manager, containing the desired components, and add it to the application's Frame.
<add>
<bean class="[Link]">
<add>
<bean class="[Link]">
<property name="text" value="Delay: "/>
</bean>
</add>
Following that Label we add a TextField. The TextField is sized so that it can comfortably display the range of
possible juggling speeds, and initialized the same way we initialized the Scrollbar: with the value of the Juggler's
animationRate property.
<add>
<bean class="[Link]" id="currentRate">
<property name="columns" value="5"/>
<property name="text">
<property name="animationRate" target="Juggler"/>
</property>
We then bind the Scrollbar’s adjustment events to the text property of our TextField so it will always display the
correct value. Note that BML will automatically convert the AdjustmentEvent’s value property from an int to a String,
so we can drop it directly into the TextField.
Since the user may edit the value of the field directly, we will want to bind the TextField’s action events to both the
Scrollbar’s value property, and the Juggler’s animationRate property.
<event-binding name="action">
<script>
<property target="scale" name="value">
<property target="currentRate" name="text"/>
</property>
<property target="Juggler" name="animationRate">
<property target="currentRate" name="text"/>
</property>
</script>
</event-binding>
</bean>
</add>
We can now close this Panel and finish <add>ing it to the South edge of the Frame. Since that's the end of our
additions, the Frame can be closed as well.
</bean>
<string value=”South”/>
</add>
</bean>
Appendix B contains the completed [Link]. The Juggler2 demo can also be found in the demos/juggler
directory.
3.2 PLAYING
To run the Juggler2 demo using the PlayerDriver:
When the Juggler starts up, the “Bee” will start juggling the “Eye”, the “Bee”, and the “M”, and the initial delay
value (110) will be displayed. Adjusting the Scrollbar's slider will affect the speed of the animation, and update
the “Delay” TextField accordingly. Directly editing the “Delay” TextField will affect the speed of the animation,
and adjust the Scrollbar’s slider accordingly.
Of course the Stop and Start buttons still work just as they did in the first version of the Juggler.
KNOWN QUIRK: Some of the shorter delay settings may actually appear to juggle more slowly. That's due to the
"stroboscope" effect of screen updates.
3.3 COMPILING
To compile the Juggler2 demo into Java code, using the CompilerDriver:
We'll demonstrate this by showing how you can add functionality to Juggler1, one piece at a time, to yield the
equivalent of Juggler2.
In order to use BML to apply updates to a running Java application, we'll need to have both the application and the
BML Player running in a single Java Virtual Machine. Rather than write a driver specifically for that purpose, let's use
the “applettool” demo, which can be found in the demos/applettool directory.
Despite its name, applettool, which is itself written in BML, can be used as an application as well as an Applet.
Leave the applettool and Juggler1 running so we can use them later in this example.
BML is an XML language, so a BML file is only allowed to have one top-level element of any kind. Since the
topFrame is the last bean we're going to want to modify in this sequence, as well as being the target of the <add>
operation, we'll use it to enclose the other operations.
Note the use of the source attribute to retrieve topFrame from the existing run-time Object Registry.
<?xml version="1.0"?>
<bean source="topFrame">
<add>
<bean class="[Link]" id="scale">
<property name="minimum" value="0"/>
<property name="maximum" value="220"/>
<property name="value">
<property name="animationRate" target="Juggler"/>
</property>
<event-binding name="adjustment">
<script>
<property target="Juggler" name="animationRate">
<property target="event:arg1" name="value"/>
</property>
</script>
</event-binding>
</bean>
<string value=”East”/>
</add>
<call-method name="pack"/>
</bean>
Earlier we asked you to leave the applettool and Juggler1 running so they'd be ready to use. If you didn't, please
follow the instructions given there before proceeding:
Ÿ The large text area in the middle of the applettool is probably still showing the BML we entered in the previous
step. Press the "Clear" button to erase it.
Ÿ Type in the BML we've just developed above, or use your system’s clipboard features to cut-and-paste the BML
into the tool... or, since this is a standard demo, just push the button labeled “Juggler1 Update 1.”
Ÿ Press the "Run" button at the bottom of the applettool screen. If the BML is correct, you should see the
Scrollbar appear along the right edge of the Juggler1 Frame, and the Frame will increase its size appropriately.
Try moving the slider, and watch the Juggler’s animation speed change.
Leave the applettool and the modified Juggler1 running so we can use them later in this example.
Appendix C contains the completed [Link]. The Juggler1a incremental BML demo can also be found in the
demos/juggler directory.
4.3 ADDING THE TEXT FIELD
Just as we added the Scrollbar to the already-running Juggler1, we can also add the “Delay” display at the bottom.
Again, this BML code should look very familiar; most of it is copied directly from Juggler2. The one significant
difference is that the TextField will initially have its editable property set to false. We will make it editable later, to
further demonstrate the incremental nature of this code.
<?xml version="1.0"?>
<add>
<bean class="[Link]" id="currentRate">
<property name="editable" value="false"/>
<property name="columns" value="5"/>
<property name="text">
<property name="animationRate" target="Juggler"/>
</property>
<call-method name="pack"/>
</bean>
Earlier we asked you to leave the applettool and Juggler1 running so they'd be ready to use. If you didn't, please
follow the instructions given above before proceeding:
Ÿ The large text area in the middle of the applettool is probably still showing the BML we entered in the previous
step. Press the "Clear" button to erase it.
Ÿ Type in the BML we've just developed above, or use your system’s clipboard features to cut-and-paste the BML
into the tool... or, push the button labeled “Juggler1 Update 2.”
Ÿ Press the "Run" button at the bottom of the applettool screen. If the BML is correct, you should see the new
panel appear at the bottom of the Juggler1 Frame, and the Frame will increase its size appropriately. If you’ve
changed the animation speed before you added this, you’ll note that since the TextField asks the Juggler for its
current value, it will show the correct value rather than the Juggler’s original speed of 110.
Move the slider, and you’ll see that both the displayed number and the animation’s speed now respond.
Appendix C contains the completed [Link]. The Juggler1b incremental BML demo can also be found in the
demos/juggler directory.
<?xml version="1.0"?>
<bean source="currentRate">
<property name="editable" value="true"/>
<event-binding name="action">
<script>
<property target="scale" name="value">
<property target="currentRate" name="text"/>
</property>
<property target="Juggler" name="animationRate">
<property target="currentRate" name="text"/>
</property>
</script>
</event-binding>
</bean>
</bean>
Earlier we asked you to leave the applettool and Juggler running so they'd be ready to use. If you didn't, please
follow the instructions given above before proceeding:
Ÿ The large text area in the middle of the applettool is probably still showing the BML we entered in the previous
step. Press the "Clear" button to erase it.
Ÿ Type in the BML we've just developed above, or use your system’s clipboard features to cut-and-paste the BML
into the tool... or, push the button labeled “Juggler1 Update 3.”
Ÿ Press the "Run" button at the bottom of the applettool screen. If the BML is correct, you should now be able to
directly change the frame delay of the Juggler by editing the TextField. Make sure to hit enter after changing the
value, to fire off the actionEvent.
You’ll notice that both the speed of the Juggler, and the position of the slider, are affected by changing the value in
the “Delay” TextField.
We have now completed the evolution of our running application from Juggler1 to Juggler2.
Appendix C contains the completed [Link]. The Juggler1c incremental BML demo can also be found in the
demos/juggler directory.
5. CALCULATOR WITH JAVASCRIPT LOGIC
This next example will serve primarily to demonstrate the usage of scripts defined in a language other than BML.
Since it is assumed that the user will have worked through the previous examples (the various Juggler-related demos),
we will not examine every line of the code; instead, we will concentrate only on the lines relevant to the scripts.
This demo consists of six TextFields contained in a Frame. When the user enters values in the top two TextFields,
some simple arithmatic results are calculated and displayed in the bottom four TextFields. What takes place between
the user entering values and the results being displayed is the responsibility of the JavaScript code. The following is
an illustration of the wiring between the components:
actionEvent
textEvent
tf1
JavaScript:
tf2
doMath()
TF-sum
TF-diff
TF-prod
TF-quo
When an actionEvent is fired by tf1, or a textEvent is fired by tf2, the JavaScript function doMath() is invoked. The
binding from tf1to doMath() is defined as follows:
<script language="javascript">
tf1 = [Link]("tf1");
tf2 = [Link]("tf2");
tfsum = [Link]("TF-sum");
tfdiff = [Link]("TF-diff");
tfprod = [Link]("TF-prod");
tfquo = [Link]("TF-quo");
parseInt = [Link];
function getInt(str)
{
return str == "" ? 0 : parseInt(str);
}
function doMath()
{
x = getInt([Link]());
y = getInt([Link]());
[Link]((x + y) + "");
[Link]((x - y) + "");
[Link]((x * y) + "");
[Link]((x / y) + "");
}
</script>
You’ll notice that this <script> is contained directly within the outermost <bean>, not within an <event-binding>.
There is an important semantic difference related to the context of a <script>: if a <script> is contained directly within
an <event-binding>, it is processed at the time of the event-firing (i.e. its execution is delayed). However, if a <script>
is contained directly within any element other than an <event-binding>, it is processed immediately (i.e. its execution
is immediate).
In the case of this demo, the <script> containing the definition of doMath() is processed when the BML code is first
executed. The two <script>s containing the invocation of doMath() are only processed when their respective events
are fired.
Note: All JavaScript code contained within a single BML script is executed in a single context. Therefore, the function
doMath() is available to the other JavaScript blocks, even though they are contained within separate <script>s. Also,
note the usage of the global variable “bsf”. “bsf” is a special variable made available to the user for the purpose of
interacting with BML’s Object Registry.
Appendix D contains the completed calc_js.bml. The calc_js demo can also be found in the demos/calc_js directory.
6. APPENDICES
<?xml version="1.0"?>
<add>
<bean class="[Link]" id="Juggler">
<property name="animationRate" value="110"/>
<call-method name="start"/>
</bean>
<string value="Center"/>
</add>
<add>
<bean class="[Link]">
<add>
<bean class="[Link]">
<property name="label" value="Start"/>
<event-binding name="action">
<script>
<call-method target="Juggler" name="start"/>
</script>
</event-binding>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="label" value="Stop"/>
<event-binding name="action">
<script>
<call-method target="Juggler" name="stop"/>
</script>
</event-binding>
</bean>
</add>
</bean>
<string value="North"/>
</add>
</bean>
<?xml version="1.0"?>
<add>
<bean class="[Link]" id="Juggler">
<property name="animationRate" value="110"/>
<call-method name="start"/>
</bean>
<string value="Center"/>
</add>
<add>
<bean class="[Link]">
<add>
<bean class="[Link]">
<property name="label" value="Start"/>
<event-binding name="action">
<script>
<call-method target="Juggler" name="start"/>
</script>
</event-binding>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="label" value="Stop"/>
<event-binding name="action">
<script>
<call-method target="Juggler" name="stop"/>
</script>
</event-binding>
</bean>
</add>
</bean>
<string value="North"/>
</add>
<add>
<bean class="[Link]" id="scale">
<property name="minimum" value="0"/>
<property name="maximum" value="220"/>
<property name="value">
<property name="animationRate" target="Juggler"/>
</property>
<event-binding name="adjustment">
<script>
<property target="Juggler" name="animationRate">
<property target="event:arg1" name="value"/>
</property>
</script>
</event-binding>
</bean>
<string value="East"/>
</add>
<add>
<bean class="[Link]">
<add>
<bean class="[Link]">
<property name="text" value="Delay: "/>
</bean>
</add>
<add>
<bean class="[Link]" id="currentRate">
<property name="columns" value="5"/>
<property name="text">
<property name="animationRate" target="Juggler"/>
</property>
<?xml version="1.0"?>
<bean source="topFrame">
<add>
<bean class="[Link]" id="scale">
<property name="minimum" value="0"/>
<property name="maximum" value="220"/>
<property name="value">
<property name="animationRate" target="Juggler"/>
</property>
<event-binding name="adjustment">
<script>
<property target="Juggler" name="animationRate">
<property target="event:arg1" name="value"/>
</property>
</script>
</event-binding>
</bean>
<string value="East"/>
</add>
<call-method name="pack"/>
</bean>
<?xml version="1.0"?>
<!-- Incremental update to Juggler1:
Retrieves the topFrame from the Registry and adds the speed display.
NOTE: This assumes that juggler1a has already been run to create the
speed control slider. Applying the updates out of order won't wire
all the events properly.
-->
<bean source="topFrame">
<add>
<bean class="[Link]">
<add>
<bean class="[Link]">
<property name="text" value="Delay: "/>
</bean>
</add>
<add>
<bean class="[Link]" id="currentRate">
<property name="editable" value="false"/>
<property name="columns" value="5"/>
<property name="text">
<property name="animationRate" target="Juggler"/>
</property>
<call-method name="pack"/>
</bean>
<?xml version="1.0"?>
<bean source="currentRate">
<property name="editable" value="true"/>
<event-binding name="action">
<script>
<property target="scale" name="value">
<property target="currentRate" name="text"/>
</property>
<property target="Juggler" name="animationRate">
<property target="currentRate" name="text"/>
</property>
</script>
</event-binding>
</bean>
</bean>
<?xml version="1.0"?>
<bean class="[Link]">
<args>
<string value="Calc demo with JavaScript logic..."/>
</args>
<add>
<bean class="[Link]">
<property name="text" value="Enter first argument: "/>
</bean>
</add>
<add>
<bean class="[Link]" id="tf1">
<property name="columns" value="10"/>
<event-binding name="action">
<script language="javascript">doMath();</script>
</event-binding>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="text" value="Enter second argument: "/>
</bean>
</add>
<add>
<bean class="[Link]" id="tf2">
<property name="columns" value="10"/>
<event-binding name="text">
<script language="javascript">doMath();</script>
</event-binding>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="text" value="Results: "/>
</bean>
</add>
<add>
<bean class="[Link]"/>
<!-- spacer for grid layout -->
</add>
<add>
<bean class="[Link]">
<property name="text" value="Sum: "/>
</bean>
</add>
<add>
<bean class="[Link]" id="TF-sum">
<property name="columns" value="10"/>
<property name="editable" value="false"/>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="text" value="Difference:"/>
</bean>
</add>
<add>
<bean class="[Link]" id="TF-diff">
<property name="columns" value="10"/>
<property name="editable" value="false"/>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="text" value="Product:"/>
</bean>
</add>
<add>
<bean class="[Link]" id="TF-prod">
<property name="columns" value="10"/>
<property name="editable" value="false"/>
</bean>
</add>
<add>
<bean class="[Link]">
<property name="text" value="Quotient:"/>
</bean>
</add>
<add>
<bean class="[Link]" id="TF-quo">
<property name="columns" value="10"/>
<property name="editable" value="false"/>
</bean>
</add>
<script language="javascript">
tf1 = [Link]("tf1");
tf2 = [Link]("tf2");
tfsum = [Link]("TF-sum");
tfdiff = [Link]("TF-diff");
tfprod = [Link]("TF-prod");
tfquo = [Link]("TF-quo");
parseInt = [Link];
function getInt(str)
{
return str == "" ? 0 : parseInt(str);
}
function doMath()
{
x = getInt([Link]());
y = getInt([Link]());
[Link]((x + y) + "");
[Link]((x - y) + "");
[Link]((x * y) + "");
[Link]((x / y) + "");
}
</script>
</bean>
26