The contour package is a simple text editor based on one of the
tutorials that comes with the JBuilder Java development environment.
The
tutorial was designed to exercise JBuilder's graphical UI development tools, and is not a particularly good example of object-oriented design: almost all of the code is contained in a single class TextEditFrame
.
Nevertheless, the step-by step development process that is described in the tutorial notes provides a good illustration of how conventional OOP fails to achieve code locality---in other words, code related to a single function is spread through a number of methods or classes.
Good locality is maintained until Step 10, when the
String
that serves as the model
for the Text Pane is connected to a file by two methods,
openFile
and
saveFile
, which are in turn
connected to the appropriate menu commands. Here the tutorial code
also introduces a "dirty bit" to record whether the file has changed
since it was last read from or written to disk, and in Step 11 this
Boolean is used to change the behavior of some of the other methods.
Our aspect-oriented version of the program maintains all of this as
the ChangeMonitor aspect. (Click
here to see it in a
separate browser window.)
Line 17 introduces a new instance variable
changed
into all objects of class
TextEditFrame
. (Why into the
Frame and not into the Model? Because the tutorial example has
no real model; it is all interface. The closest it comes to a model
of the file is a Java String
.)
Lines 19 through 26 take care of resetting
changed
when necessary:
immediately after a successful
openFile
,
saveFile
or
menuItem1_actionPerformed
(corresponding to the File > New
event), changed
is assigned
false.
Because opening or saving
a file might fail, the weave checks the result of the method
(thisResult
, line 24) before
assigning to changed
.
Lines 28 to 37 set changed
whenever the textValueChanged
event handling method is invoked. The body of this method is:
void textArea1_textValueChanged(TextEvent e)
{statusBar.setText("Editing " + currentFileString());
}
Since there is no need to set the text in the status bar more than
once, if the before weave finds that
changed
is already true, it
returns immediately. However, if
changed
was false, it sets
changed to true and then falls through to the ordinary method body,
which will update the status bar as expected.
Lines 39 to 49 optimize away the
saveFile
action when the file has
not changed; in this case the before advice simply beeps and
returns.
Lines 51 to 79 introduce a new method
okToAbandon
into
TextEditFrame
objects; it returns
true if it is permissible to abandon a currently active editor
buffer. The final two advise weaves (lines 81 to 89 and lines 91 to
98) use this method to ensure that the contents of a changed editor
buffer are not abandoned in error when a file is opened, or when the
buffer is cleared, or when the user quits the editor.
The second aspect (in file Caption.java) contains all of the code
related to updating the caption at the top of the window. First we
introduce into TextEditFrame
a
method updateCaption(...),
and a
variable currentCaption
that
maintains a cached copy of the current caption, and which is used to
avoid unnecessary calls to the windowing system. Five pieces of
advice are then offered: after advice to the
TextEditFrame
constructor, and
the methods for openFile
,
saveFile
and the New menu event.
and before advice on the method that handles the
textValueChanged
event.
Some care is necessary to ensure that the two aspects and the
original code interact correctly. For example,
updateCaption(...)
takes a
Boolean argument that tells it whether the buffer is "dirty", and
which is rendered as an asterisk in the caption. This is much cleaner
than relying on the changed variable, which is part of another
aspect, because changes to that aspect could introduce subtle bugs.
Similarly, the advise weaves that reset the caption when a new buffer
is opened must be after advise, because the
okToAbandon
method called from
the before advise on the same method might have prematurely
terminated that method's execution.
The aspect weaver generates Java files that can be compiled and run in any Java programming environment. Although not intended for human consumption, the generated code is quite readable, and viewing it offers an interesting perspective on the weaving process.