Formal Modelling of Java GUI Event Handling: 1 Motivation
Formal Modelling of Java GUI Event Handling: 1 Motivation
Jessica Chen
1 Motivation
With the advances of software development and the increasing use of web pro-
gramming technologies, more and more applications now make use of Graphical
User Interface (GUI) to enhance user friendliness. In particular, as Java is gain-
ing its increasing popularity, many web applications now involve graphical user
interface developed with Java Swing and AWT.
However, programming in Java Swing and AWT can be quite error-prone due
to the implicit nondeterminism caused by the complex event handling realized
through the use of multiple threads. To write correct programs thus requires a
good understanding of Java multithreading and the GUI event control. Such a
good understanding is hard to achieve without a precise definition of the working
context. In this paper, we define the operational semantics in terms of labelled
transition systems for the behavior of a GUI-based Java application/applet at
a lower level where event handling mechanism is explicitly specified. This is
essential for the software programmers to get a better understanding of the
internal event control and thus avoid potential errors in their coding.
No programmer can be perfect: both faults and errors are quite common
in software industry practice. In order to detect system faults and errors, vari-
ous static analysis techniques, formal verification techniques, and dynamic test-
ing/debugging techniques have been explored. Although testing has always been
our primary device to guarantee the quality of the systems, some concurrency
C. George and H. Miao (Eds.): ICFEM 2002, LNCS 2495, pp. 359–370, 2002.
c Springer-Verlag Berlin Heidelberg 2002
360 Jessica Chen
control related errors are hard to find because the tests are not repeatable due
to the nondeterminism involved. The Java GUI event systems are typically of
this kind because of the implicitly employed multithreading in the GUI event
handling. For these systems, software verification under certain formalisms and
methodologies usually gives us higher confidence about the system. The formal
model we defined for the Java event handling is the basis for formally reasoning
about the correctness of the a GUI-based Java application/applet against certain
properties that, due to the nondeterminism involved, may be hard to detect by
ordinary testing techniques.
In the following, we first give in Section 2 a brief review of Java GUI event
handling mechanism. Then we present our operational semantics followed by an
example in Section 3 and 4. In Section 5 we discuss how to detect errors via
labelled transition system. The related work is provided in Section 6 and we
have Section 7 for conclusion and final remarks.
An event listener is an object who listens for specific types of events generated
on specific GUI objects. Each event listener has pre-defined methods (called event
handlers) to be executed for the events that it listens to.
In order to have the Java run-time system process GUI events, the program-
mer needs to perform two tasks:
– register an event listener for each specific type of event on each specific GUI
object;
– provide implementation of the event handlers to handle such events for each
event listener.
Figure 1 shows a very simple Java application with Swing. It constructs a
JFrame p which contains a JTextField t. l is an event listener object that is
registered to listen to the action events on t. l handles such events by calling its
method actionPerformed which sets t to be non-editable.
Formal Modelling of Java GUI Event Handling 361
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
When the user interacts with the GUI, all triggered events are put into an
event queue. An internal dispatching thread is dedicated to dispatch the events
from the event queue: it keeps picking the events from the head of the event
queue and dispatching it to the proper event listeners according to the event
type and the associated event context. If there is no listener registered for this
event type and context, the event will be simply ignored. If there are some
listeners registered, then their corresponding predefined event handlers will be
executed.
There is a special kind of events that requires the dispatching thread to
perform by itself the run() method defined on the event context. We use runnable
to denote this type.
The event context is not guaranteed to be thread-safe in general: When an
event is dispatched to a listener, the event handler may be executed in a thread
other than the one that performed the listener registration. The choice of which
thread to use is made by the service provider. Furthermore, when an event is
dispatched to multiple listeners, the service provider will normally choose to
execute the event handlers concurrently in separate threads.
In the above example, the JFrame constructor is called by an implicitly cre-
ated thread (we call it main below) to execute the main() method. Within this
constructor, we have registered l for action events on t. However, the dispatching
thread may assign a thread other than main to execute the event handler of l.
This makes the concurrent executions of event handler and of the JFrame con-
struction possible. As a consequence, while a separate thread is setting t to be
non-editable according to the event handler, it is possible that the main thread
will be trying to set t to be editable. This causes the simultaneous access to the
same GUI object via different threads and hence implies potential errors.
Although here we have only shown a very simple example, the real applica-
tions may take quite complicated forms and thus make the potential errors hard
to see by code walk through. Like in many concurrent systems, to detect such
concurrency-related errors via ordinary testing techniques is also hard mainly
because the tests are not repeatable.
An event listener registration is a triple (gd, tp, ld) where gd is the identifier of
the GUI object, i.e. the context of the event; tp is the name of the event type;
and ld is the identifier of the listener object. Such an event listener registration
expresses that the object with identifier ld is registered to listen to the events of
type tp on GUI object with identifier gd.
In this work, we consider only the following restricted set of atomic actions:
A = {read(od, f d), write(od, f d, v), reg(gd, tp, ld), dereg(gd, tp, ld)
| od ∈ Od, f d ∈ F d, v ∈ V, gd ∈ Gd, tp ∈ T P, ld ∈ Ld}
A sequential program execution can be constructed as a process term [19] based
on a set of atomic actions and a set of operators. For simplicity, we only con-
sider the sequential execution operator denoted by a semicolon. Extension of this
framework to include other operators such as choice, recursion, etc. is straightfor-
ward. For convenience, we assume that such a sequence is a sequence of actions
ended by a special symbol stop.
364 Jessica Chen
antecedent
consequent
where ti are new threads (1 ≤ i ≤ k), and T does not include the behavior of
the dispatching thread.
The first rule is used to define the possible evolution of the system caused by
the event dispatching of the dispatching thread when the first event of the event
queue is a GUI event and there are listeners registered in the current R to handle
it. In this case, the whole system makes the related transition corresponding to
the one by the dispatching thread while all other threads remain in the same
state. In the ending state of the system, the GUI event is removed from the event
queue Q, and there are new threads generated to perform each of the handling
tasks of the listeners registered for this event. Note that the dispatching thread
should have no code to execute (i.e. in state stop) in order to dispatch events
from the event queue, otherwise it has to execute its own code first.
Rule A3 (Runnable)
Rule A4 (Trigger)
Rule (A4) expresses our simulation of the GUI input from the end users. An
end user can trigger GUI events at any time as long as the context GUI object
366 Jessica Chen
is currently visible by the end user. Here we use O(od,f ) to denote the value of
field f of object od in the current state.
Rules (A5) and (A6) define the possible evolution of the system caused by
an action to read from the main memory or write into the main memory. The
thread that executes such an action can be either of a program thread or the
dispatching thread that is executing a run() method. Rules (A7) and (A8) show
the possible system moves caused by the registration and deregistration of the
event listeners to the specified event types on the specified GUI objects. For the
lack of space, we do not present these structural rules formally.
Given an initial state, the above eight structural rules allow us to associate
to it a labelled transition system whose states are those reachable from the ini-
tial state, via the transitions inferred by using the structural rules. The labelled
transition system generated from the initial state describes all the possible evo-
lutions, and hence constitutes our model of the system.
4 An Example
In the above given program, there are four objects that we are interested in
(without confusion, we use the object reference names as their identifiers):
Thus, we have
– Ld = {l};
– Gd = {p, t};
– T d = {main, dt};
– TP contains all the names of the event types that can be triggered on GUI
object p and t, such as action event (denoted by ae below), focus event, text
event.
– M = {(l, ae, write(t, enabled, f alse); stop)}
5 Detecting Errors
The most prominent significance in defining operational semantics on the GUI
event handling mechanism lies in formally reasoning about the correctness of the
GUI-based programs.
As we know, process algebras e.g. CCS [19], CSP [13], ACP [1], have been
well studied for describing concurrent and multi-process systems. For finite state
processes (processes that can be interpreted on finite transition systems), various
practical model checking tools have been developed to verify whether a process
satisfies certain properties (see e.g. [3,7,10,15,18,26]), where the properties ac-
tually characterize the requirements of the system and can be described in a
formula of a modal/temporal logic such as CTL [9], µ-calculus [16,25]. Since
most of these tools are based on transition systems, we can make use of their
techniques, or even reuse existing tools to verify certain properties over the tran-
sition systems we obtained for the GUI event handling.
For example, we know that GUI update is not thread-safe. We need to guaran-
tee that at each moment, there is at most one thread accessing the GUI objects.
This can be expressed as an invariance that in the given transition system, there
is no two consecutive actions (labels in our setting) (t1 , op1 ) and (t2 , op2 ) such
that op1 and op2 both access some GUI objects, i.e. for some t1 , t2 ∈ T d, od1 ,
od2 ∈ Gd, f1 , f2 ∈ F d, v1 , v2 ∈ V ,
368 Jessica Chen
t1 = t2 ,
op1 = write(od1 , f1 , v1 ) or op1 = read(od1 , f1 ),
op2 = write(od2 , f2 , v2 ) or op2 = read(od2 , f2 ).
This statement can be easily formulated in, for example, modal µ-calculus or
action-based CTL [20]. Similarly, we can formulate an invariance to express that
at each moment, there is at most one thread accessing an (not necessarily GUI)
object field.
The violation of these invariance are mainly due to the nondeterministic as-
signment of the threads to execute the event handlers, and the possibility of
hitting the related errors is relatively low. As a consequence, it becomes very
hard, if not impossible, to detect them using ordinary testing techniques. With-
out the help of verification tools, such errors would easily slip into product in
customers hands.
6 Related Work
Acknowledgements
This work is supported in part by the Natural Sciences and Engineering Research
Council of Canada under grant number RGPIN 209774.
References