0% found this document useful (0 votes)
48 views14 pages

Aop@Work:: Enhance Design Patterns With Aspectj, Part 1

Some Aop remarks from IBM

Uploaded by

George Terziev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
48 views14 pages

Aop@Work:: Enhance Design Patterns With Aspectj, Part 1

Some Aop remarks from IBM

Uploaded by

George Terziev
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

AOP@Work: Enhance design patterns with AspectJ, Part 1

Country/region [select]

Terms of use

All of dW
Home

Products

developerWorks

Services & solutions

Support & downloads

My account

> Java technology >

AOP@Work: Enhance design patterns


with AspectJ, Part 1
AOP makes patterns lighter, more flexible, and easier to
(re)use
Level: Intermediate

Contents:
AOP for patterns
The Adapter pattern
A Java-language Adapter
An AspectJ Adapter
The Decorator pattern

Nicholas Lesiecki ([email protected])


Programming Instructor, Google
17 May 2005

A Java language Decorator


An AspectJ Decorator
Conclusion to Part 1
Resources

Design patterns have long been part of the experienced developer's


tool chest. Unfortunately, because patterns can affect multiple classes,
they can also be invasive and hard to (re)use. In this two-part article,
the third in the AOP@Work series, Nicholas Lesiecki shows you how AOP
solves this problem by fundamentally transforming pattern implementation. He
examines three classic Gang of Four (GoF) design patterns (Adapter,
Decorator, and Observer) and discusses the practical and design benefits of
implementing them with aspect-oriented techniques.

Download
About the author
Rate this article

Related content:
Improve modularity with aspect-oriented programming
Develop aspect-oriented Java applications with Eclipse and AJDT
AOP@Work series page
Enhance design patterns with AspectJ, Part 2

What is a design pattern? According to Design Patterns: Elements of Reusable ObjectOriented Software (commonly referred to as GoF; see Resources for details):

Subscriptions:
dW newsletters

A design pattern systematically names, motivates, and explains a general design that addresses a
recurring design problem in object-oriented systems. It describes the problem, the solution, when to apply
the solution, and its consequences. It also gives implementation hints and examples. The solution is a
general arrangement of objects and classes that solve the problem. The solution is customized and
implemented to solve the problem in a particular context.
After years of successfully applying patterns to solve problems in OO systems, I found myself nodding along with this
definition. Patterns were a great way to talk to my fellow programmers about design, and they represented best practices
that addressed recurring design problems. So it was a bit of a shock to me when I attended a talk by Stuart Halloway where
he suggested an alternate title for the GoF: "Workarounds for things that are broken in C++." His point was that what exists
as a "pattern" in one language can be subsumed into the language itself in a different paradigm. He went on to give the
example of Factories -- useful in the Java language, but less useful in Objective-C, which lets you return subtypes from a
constructor.
I had to think about it for a while before I realized that the two sides were saying the same thing: design patterns give us a
vocabulary for expressing concepts that can't be said directly in the programming language.
So where does AOP come in? For OOP, we have the GoF patterns, which give us a consistent, though sometimes
cumbersome, way of working with common concepts like observers and decorators. AOP builds on OOP to give us a direct
way of expressing crosscutting concerns. It turns out that some of the GoF patterns are about crosscutting and can be
expressed directly in AOP. So what you'll notice is that some of the patterns that involve many classes can be expressed
with a single aspect. Some patterns become easier to use because they involve less code. Some are so well supported that
they almost disappear. Others are strictly tied to OOP (for example, the patterns dealing with class structures) and remain
unchanged when used in conjunction with AOP.

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (1 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

This article explores pattern implementation with AOP (specifically AspectJ). I chose
to tackle GoF patterns because of their widespread popularity and general utility. In
this part of the article, I set up some criteria for analyzing the impact of patterns and
then go on to investigate the Adapter and Decorator patterns. Adapter demonstrates
the benefits of static crosscutting, while Decorator reveals itself as a disappearing
pattern. In Part 2, I offer a more in-depth study of the Observer pattern, which does
not disappear, but sees major benefits when implemented in AspectJ. Part 2
illustrates how AspectJ allows patterns to be converted into reusable base aspects,
thus allowing you to download prebuilt pattern libraries -- an exciting prospect for the
pattern enthusiast.

Why apply AOP to design patterns?


I previously claimed that many patterns are crosscutting, but of course I wasn't the
first one to think of this. A recent research paper analyzed the GoF patterns and
found that 17 out of the 23 patterns exhibited some degree of crosscutting. (The
paper is Jan Hannemann and Gregor Kiczales's "Design Pattern Implementation in
Java AspectJ," see the Resources section for more details.) If AOP promises to help
with crosscutting, what kind of benefits can you expect to see from using it on design
patterns? I'll start by answering that question in general terms, and then set up a
framework through which I'll consider each design pattern.

About this series


The AOP@Work series is intended for
developers who have some background in
aspect-oriented programming and want to
expand or deepen what they know. As with
most developerWorks articles, the series is
highly practical: you can expect to come
away from every article with new
knowledge that you can put immediately to
use.

Each of the authors contributing to the


series has been selected for his leadership
or expertise in aspect-oriented
programming. Many of the authors are
contributors to the projects or tools covered
in the series. Each article is subjected to a
peer review to ensure the fairness and
accuracy of the views expressed.

Please contact the authors individually with


comments or questions about their articles.
To comment on the series as a whole, you
may contact series lead Nicholas Lesiecki.
See Resources for more background on
AOP.

Benefits of using AOP on design patterns


The first key benefit of AOP is the ability to localize the code for a given design
pattern. This means that the pattern can often be realized in a single aspect or a pair of closely related aspects. (This
stands in contrast to a Java-language implementation, where a pattern application can spread across several classes.)
Being able to see all of the code in a single location leads to several practical benefits. First, readers of the code can
understand the pattern more easily if all of its interactions are visible in one place. Second, if developers need to alter a
pattern implementation, they can make that change in one place, instead of chasing the pattern fragments throughout the
system. Third, developers can use meaningful names to describe the aspect that encapsulates the pattern, giving textual
clues as to the intent of the pattern to future maintainers. For example you could name an aspect SensorAdapter,
indicating that you had applied the Adapter pattern to sensors.
The other key benefit of an AspectJ pattern implementation is obliviousness. In other words, classes that play a role in the
pattern do not necessarily have to be aware of that role. This benefit results directly from localization -- because the pattern
is localized in an aspect, it does not invade its participants. Obliviousness makes the code for pattern participants easier to
understand. Not only that, but obliviousness makes pattern composition a great deal easier. In a Java-language
implementation, if a class participates in multiple patterns, the pattern machinery can quickly obscure its core meaning.
Classes that do not know about their participation in a pattern can also be reused in other contexts. You'll see a concrete
example of this in Part 2 of the article.
These benefits allow for code-level reuse of some patterns. The concepts and
structure of design patterns have always been reusable. Anyone who wanted to
implement the Observer pattern could pull out the GoF book and meld the pattern into
their code. But with aspect-orientation, you can spare yourself the trouble by
downloading the ObserverProtocol aspect (it's available at the Design Patterns
project; check the Resources section). Beyond the saved implementation effort, codelevel reuse also allows tighter coupling of pattern code and documentation. For
example, I can browse the javadocs for ObserverProtocol and understand its intent
and structure without having to pick up a separate textbook.

A framework for analysis


Each pattern description follows a common structure. I'll begin with an example
problem and provide a general description of the pattern. Then I will describe how to
implement the pattern, first in the Java language and then in the AspectJ language.
After each implementation I will describe what makes the pattern crosscutting and
what effects that version of the pattern has on understanding, maintaining, reusing,

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (2 of 14)5/19/2005 5:48:03 AM

What is crosscutting?
Programs often exhibit behavior that does
not fit naturally into a single program
module, or even several closely related
program modules. The aspect community
describes this type of behavior as
crosscutting because it cuts across the
typical divisions of responsibility in a given
programming model. In OO programming,
for instance, the natural unit of modularity
is the class, and a crosscutting concern is
a concern that spans multiple classes.
Thus, if a design pattern contributes
behavior to three otherwise distinct
classes, that design pattern can be said to
crosscut those classes. Crosscutting leads
to code scattering (related code does not
localize with other related code) and code
tangling (related code sits next to unrelated
code). This scattering and tangling makes
it difficult to reason about the system. For a

AOP@Work: Enhance design patterns with AspectJ, Part 1

and composing the code.

refresher on AOP concepts like


crosscutting, see the Resources section.

Click the Code icon at the top or bottom of this article (or see Download) to download
the complete source for upcoming examples.

The Adapter pattern


The first pattern I'll consider in detail is Adapter. Adapter is all about compatibility. The pattern allows classes to interact that
otherwise couldn't because of incompatible interfaces. To implement Adapter in Java code, you wrap a class (the target
class) with a special Adapter class that translates the API of the target class into one that clients expect or can more easily
make use of.

The setup: Providing an aggregated sensor readout


Let's say you're designing a space vehicle, and you've been asked to provide a readout of all of the critical sensors in the
spacecraft. Because you're extending an existing system, convenient Java classes already exist for each sensor you need
to access. For example, you can access a temperature gauge with the following class:

public class TemperatureGauge {


public int readTemperature(){
//accesses sensor internals
}
}

You can access a radiation sensor with:

public class RadiationDetector {


public double getCurrentRadiationLevel(){
//read radiation somehow
}
}

Some of these sensor classes were written by other team members, some by third-party vendors. What you would like to
do is to provide a display of each sensor's status, so that a mission commander can see at a glance whether his craft is in
trouble. Here's an example of what you're looking for. (The real display would probably involve flashing red lights and
klaxons, but I'll stick to text for now.)

Readout:
Sensor 1
Sensor 2
Sensor 3
Sensor 4

status
status
status
status

is
is
is
is

OK
OK
BORDERLINE
DANGER!

You could accomplish a display like this using the following method:

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (3 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

public static void main(String[] args){


RadiationDetector radiationDetector = //find critical detector
TemperatureGauge gauge = //get exhaust nozzle gauge
List allSensors = new ArrayList();
allSensors.add(radiationDetector);
allSensors.add(gauge);
int count = 1;
for (Sensor sensor : allSensors) {
//How to read each type of sensor...?
}
}

So far, so good, but how do you read each sensor without resorting to ugly if(sensor instanceof XXX) checks? One
option is to modify each sensor class to have a getStatus() method that interprets the sensor's readings and returns a
String, as shown here:

if(this.readTemperature() > 160){


return "DANGER";
}
return "OK"

Doing this introduces unrelated status-display code into multiple classes, adding to their complexity. Further, there might be
practical limitations (such as having to recompile a third-party class). That's where the Adapter pattern steps in.

A Java-language Adapter
The traditional implementation of the Adapter pattern works by wrapping each target class with a class that implements a
convenient API. In this case, you would create a common interface called, say, StatusSensor, shown here:

public interface StatusSensor {


String getStatus();
}

With this common interface in place, you could implement the readout method like this:

for (StatusSensor sensor : allSensors) {


System.out.print("Sensor " + count++);
System.out.println(" status is " + sensor.getStatus());
}

The only remaining challenge is to make each sensor conform to the interface. The Adapter classes accomplish this. As
you can see in Listing 1, each Adapter stores the sensor it wraps in a member variable and uses that underlying sensor to
implement the getStatus method:
Listing 1. Adapter classes and client code

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (4 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

//Adapter classes
public class RadiationAdapter implements StatusSensor {
private final RadiationDetector underlying;
public RadiationAdapter(RadiationDetector radiationDetector) {
this.underlying = radiationDetector;
}
public String getStatus() {
if(underlying.getCurrentRadiationLevel() > 1.5){
return "DANGER";
}
return "OK";
}
}
public class TemperatureAdapter implements StatusSensor {
//...similar
}
//glue code to wrap each sensor with its adapter...
allSensors.add(new RadiationAdapter(radiationDetector));
allSensors.add(new TemperatureAdapter(gauge));

The listing also shows "glue code" that wraps each sensor with the appropriate Adapter before the readout. The pattern
does not dictate that this glue code appear in any particular place. Likely locations include "just after creation" and "just
before use." The sample code places it just before it adds the sensor to the readout collection.

Analysis of the Java language Adapter


The Adapter pattern fares reasonably well in its traditional implementation. What makes this crosscutting? Well, the "status"
concern cuts across several different sensor classes. If you were to co-locate the Adapter classes in a package, the OO
implementation of this pattern would modularize fairly well. The package would become an "Adapter Module." The
wrapping idiom prevents the sensors from knowing about the pattern, which leads to looser coupling. Unfortunately, the
part of the application that did the wrapping would need to know about both the Adapters and the sensors they applied to.
So the glue code location would also be crosscut by the pattern.
Now, here's how the Java language Adapter stacks up against my evaluation criteria:

Understanding: Evocatively named SensorAdapters co-located in a package make the intent of this pattern clear.
Unfortunately, the glue code's location might be far from the Adapter package. Since the glue code area is
unstructured, you might overlook it while attempting to understand the pattern or trip over it while trying to
understand the code it tangles with.
You must also take care to deal with issues of object identity. That is, if wrapped and unwrapped versions of the
same object coexist in a system, you will have to sort out whether they should be regarded as equal.

Reusing: To reuse this pattern, you must reimplement it from scratch.


Maintaining: As you add new sensors to the readout, you must add new adapter classes and update the glue code
to wrap them.
Composing: Imagine you want to involve the sensors in another pattern. The sensors are oblivious to the Adapter,
so they would be unaffected. However, this a two-edged sword. Should the new pattern consider the adapted or
the unadapted version of the sensor to be its object?

An AspectJ Adapter
As with other design patterns, the AspectJ implementation of Adapter preserves the intent and concepts of its cousin. The
implementation uses intertype declarations, an important type of crosscutting support that gets less airtime than pointcuts
and advice. If you need a refresher on static crosscutting, check out the Resources section for appropriate pointers.
As with the pure OOP version, the AOP version of Adapter requires the StatusSensor interface. However, instead of using
separate wrapper classes, the AspectJ version uses the declare parents form to make the various sensors implement
http://www-128.ibm.com/developerworks/library/j-aopwork5/ (5 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

StatusSensor directly, as you see here:

public aspect SensorAdapter {


declare parents :
(TemperatureGauge || RadiationDetector)
implements StatusSensor;
}

Now the sensors should conform to the interface. But they do not yet implement the interface (a fact that the AspectJ
compiler will happily point out to you). To complete the pattern implementation, you must add intertype method declarations
to the aspect to make each sensor conform. The code below adds the getStatus() method to the TemperatureGauge
class:

public String TemperatureGauge.getStatus(){


if(this.readTemperature() > 160){
return "DANGER";
}
return "OK";
}

The AspectJ version of the readout class looks the same as the version implemented in the Java language, except that no
glue code is necessary to wrap the sensors. Each sensor is its own wrapper.

Analysis of the AspectJ Adapter


The key benefit of implementing Adapter with AspectJ is localization. The entire
pattern is contained within a single aspect, rather than in two (or more) separate
adapter classes and an unstructured "wrapping" location. Here's how the AspectJ
implementation fares according to my criteria:

Understanding: The lack of wrapping removes the need to look anywhere


other than the Adapter aspect to understand the pattern. No wrapping also
removes the need to deal with object identity issues.
Reusing: The AspectJ version isn't any more or less reusable than the other
version.
Maintaining: Because each new sensor involves only writing a method
(rather than a full class), extending the AspectJ implementation should be
slightly easier. As the number of adaptees grows or the logic required for
each adaptation becomes complex, you may find that a single aspect
becomes unreasonably long. In this case, you can split the aspect into
several. Splitting the aspect loses some of the localization benefits, but
preserves the other benefits.
Composing: You can compose multiple patterns easily because there are no
wrapping-coordination issues to deal with.

The upshot is that both the Java and AspectJ implementations do a good job of
staying out of the way of the sensor classes. However, only the AspectJ version stays
out of the rest of your application. Is this a major advantage? It probably depends on
whether your application exhibits any of the complicating properties described in the
analyses. If I were using AspectJ on a project, I would definitely use it to implement
Adapter, although I wouldn't introduce AspectJ just to solve this problem. The next
pattern, Decorator, provides some more compelling advantages.

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (6 of 14)5/19/2005 5:48:03 AM

Modifying third party code


Astute readers probably recall that in the
setup for the example, I mentioned that
one of the sensors came from a third-party
vendor and that this would prevent you
from easily adding a method to the class in
the Java-language implementation. In
contrast, the AspectJ compiler provides the
ability to affect compiled bytecode in order
to allow developers to apply aspects to a
wider range of classes. Adding a
compilation step in which the
SensorAdapter aspect was woven into the
third-party jar would let you use the
adapted version of the class seamlessly.

Some developers may worry about the


ramifications of modifying bytecode without
possessing the corresponding source
code. In some cases, this sort of
modification violates license terms (for
example, it's widely understood that
modifying classes provided by Sun
Microsystems violates the corresponding
license). In other cases, creating invasive
modifications to a class without a solid
understanding of its internals could
introduce subtle bugs. In this case,
however, the modifications serve only to
supplement the functionality of the target
class and interact only with its public
interface. Assuming that the provider of
RadiationDetector does not forbid
modification to its classes, there's no more
reason to be concerned about the AOP
version of Adapter than there is about the
OOP version.

AOP@Work: Enhance design patterns with AspectJ, Part 1

The Decorator pattern


Decorator is an interesting pattern to consider from an aspect-oriented perspective because it's one of the patterns that
comes closest to "disappearing" with the capabilities introduced by an aspect-oriented language such as AspectJ. Why is
this? A closer look at how Decorator evolves in both aspect- and object-oriented implementations should make it clear.
The Decorator pattern aims to add capabilities dynamically to an existing object. The canonical example given in the GoF
book involves literal decoration. In their example, a GUI component class is wrapped in a decorator class that adds a
border, or perhaps scrollbars, to the display of the component. The Java Class Libraries feature Decorator prominently, with
the methods on java.util.Collections that decorate a Collection so that it becomes unmodifiable or synchronized, as
well as a rich variety of IO streams that can buffer, inflate, or monitor other streams.

The setup: Monitoring file reads


To add spice to this example, I chose to stick with the Decorators in the Java distribution and see what it would take to
replicate one of them in AspectJ. One of the decorators I found intriguing was ProgressMonitorInputStream from javax.
swing. According to the documentation, ProgressMonitorInputStream monitors the progress of reading an underlying
input stream.
To demonstrate decoration in action, I've written a simple GUI that reads a file. You can view the code for reading the input
stream in Listing 2 and see screenshots of the running app in Figure 1. (You can also play with the full source of the
example by clicking on the Code icon at the top or bottom of this page.)
Figure 1. The ProgressMonitor for the stream

You may wish to have the javadocs or indeed the source code for java.io and ProgressMonitorInputStream open
beside you as you consider the next section; see Resources for further reference.

A Java language Decorator


In the Java language, you realize the Decorator pattern by first creating an AbstractComponent interface (or class) that
both base implementations (sometimes referred to as ConcreteComponents) and decorators can conform to. In this
example, the AbstractComponent is java.io.InputStream, which defines the interface both for FileInputStream (the
ConcreteComponent) and BufferedInputStream (a ConcreteDecorator).
Although it is not strictly necessary, Decorator implementations often feature an AbstractDecorator that maintains a
reference to the decorated component and provides the basic decoration mechanics without adding any additional
http://www-128.ibm.com/developerworks/library/j-aopwork5/ (7 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

behavior. In java.io, FilterInputStream provides this functionality. Finally, a ConcreteDecorator extends the
AbstractDecorator, overrides methods requiring decoration, and adds behavior before or after invoking the same method
on the decorated component. In this case, ProgressMonitorInputStream plays the ConcreteDecorator.
Glancing at Sun's implementation of ProgressMonitorInputStream (which I won't reprint here because of licensing
concerns), you can see that it instantiates a javax.swing.ProgressMonitor upon creation. After every read method, it
updates the monitor with a count of how many bytes have been read from the underlying stream. The separate
ProgressMonitor class determines when to pop up a monitoring dialog and updates the visual display.
To use ProgressMonitorInputStream, you simply need to wrap another input stream (as in Listing 2) and be sure to refer
to the wrapped instance when doing reads. Notice the similarity here between the Adapter and Decorator patterns: both
require programmatic application of the additional behavior to the target class.
Listing 2. Monitoring an InputStream
private void actuallyReadFile() {
try {
InputStream in = createInputStream();
byte[] b =new byte[1000];
while (in.read(b) != -1) {
//do whatever here
bytesRead+=1000;
}
bytesReadLabel.setText("Read " + (bytesRead/1000) + "k");
bytesRead = 0;
in.close();
} catch (Exception e) {
//handle...
}
}

private InputStream createInputStream() throws FileNotFoundException


{
InputStream stream = new FileInputStream(name.getText());
stream = new BufferedInputStream(stream);
//_this_ is a JPanel GUI component
stream = new ProgressMonitorInputStream(
this, "This is gonna take a while", stream);
return stream;
}

Analysis of the Java language Decorator


From looking at the example, it may seem that nothing could be easier than using the Decorator pattern. However, don't
forget that to make the example work, Sun implemented InputStream, FilterInputStream, and
ProgressMonitorInputStream -- a non-trivial amount of code.
In the example, the concern of monitoring crosscuts the InputStream. More generally, the decoration crosscuts the
decoration target. Further, the decoration concern may cut across the application. For example, users could demand a
ProgressMonitor for all file inputs. (Lest you think this is an artificial example, ask yourself how many times you've used
an input stream without buffering it.)
Now let's look at the remaining criteria:

Understanding: Once you know Decorator is at work, it's fairly easy to comprehend. But I'll never forget the
confusion I felt the first time I cracked open java.io and tried to make sense of the wealth of machinery classes
that made up Decorator as applied to streams. Although a quick tutorial could have easily set me straight, there
was no easy way to arrive at a comprehension of the pattern just from looking at the code. A more concrete
measure of comprehension burden is lines of code. I'll take a look at line counts after examining the AspectJ
implementation. It's also worth noting that, because it uses wrapping, Decorator suffers from the same object
identity issues that affect Adapter.

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (8 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

Reusing: To reuse this pattern implementation, you must reimplement it.


Maintaining: There are a couple of key maintenance scenarios. In the first, you add a new decorator to an existing
implementation. Depending on the number of methods in the Decorator, this could be tedious, but it's certainly not
hard. In the second scenario, you add a new operation to the AbstractComponent (that is, InputStream). This
means updating all of the existing decorators to reflect the new operation and making a decision at each one
whether the decoration should apply to the new method.
Composing: Because the decorators and the component share a common interface, Decorator allows for
transparent composition of decorators on a given instance. (Just look at Listing 2, where the code buffers and
monitors the input stream.) This is great, especially because the decoration targets do not have to be aware of
being decorated.

An AspectJ Decorator
In their paper, Hanneman and Kiczales state that
Using AspectJ, the implementation of some patterns completely disappears, because AspectJ language
constructs implement them directly. This applies to [Decorator].
Taking a look at the Motivation section for Decorator in the GoF book, it becomes obvious why this would be the case:
The decorator forwards requests to the component and may perform additional actions (such as drawing a
border) before or after forwarding. Transparency lets you nest decorators recursively, thereby allowing an
unlimited number of additional responsibilities.
What is advice after all, but the ability to transparently add additional "actions" to any operation? In a sense, AspectJ lets
you decorate any method. To see how this plays out in a real system, you can examine the monitoring of input stream
reads in AspectJ.

Identifying decorated operations


To correctly implement monitoring, the aspect must identify read operations on the stream. You do this by writing a pointcut
that picks out read operations:

pointcut arrayRead() :
call(public int InputStream+.read(..));

Now you can apply some advice of the following general form:

after() returning (int bytesRead) :


arrayRead()
{
updateMonitor(bytesRead);
}

This advice uses the returning form to expose the return value of the method call. The number of bytes read is then fed to
a private method on the aspect: updateMonitor(). This method takes care of the details of updating the actual
ProgressMonitor (more on this later).

Exposing relevant context


The solution so far is simple. However, it turns out that the ProgressMonitor class requires a few more things to do its job.
Specifically, it needs a GUI component to tie the monitoring dialog to. You saw this requirement in the traditional
http://www-128.ibm.com/developerworks/library/j-aopwork5/ (9 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

implementation:

//this is a JPanel GUI component


stream = new ProgressMonitorInputStream(this, "This is gonna take a while", stream);

To obtain the GUI component it needs, the aspect must bind it in the pointcut so that it can be used by the advice. Listing 3
contains the revised pointcut and advice. Notice that the fromAComponent() pointcut makes use of the primitive cflow()
pointcut. In essence, the pointcut is saying "select all join points that occur as a result of the execution of a method on a
JComponent and expose that component for use in advice."
Listing 3. Ferrying context to the monitor using cflow
pointcut arrayRead(JComponent component, InputStream is) :
call(public int InputStream+.read(..)) && target(is)
&& fromAComponent(component);
pointcut fromAComponent(JComponent component) :
cflow(execution(* javax.swing.JComponent+.*(..))
&& this(component));
after(JComponent component, InputStream is) returning (int bytesRead) :
arrayRead(component, is)
{
updateMonitor(component, is, bytesRead);
}

Maintaining state
To make the aspect widely applicable (and to accurately mimic the other implementation), the aspect must maintain state.
That is, it should pop up a unique progress monitor per monitored stream. AspectJ offers several options for dealing with
this. The best choice for this aspect is probably to maintain per-object state storage using a Map. This technique will
reappear in my implementation of the Observer pattern, so take note! (Other ways to store state specific to an object
include intertype declarations and pertarget/perthis aspects, but considering these concepts is beyond the scope of this
article.)
To implement state storage, you first declare a WeakHashMap that takes a stream as a key and stores a monitor as a value.
You want to use a WeakHashMap because WeakHashMaps will not prevent their keys from being garbage collected if the keys
are no longer in ordinary use. This best-practice prevents the aspect from holding references to defunct objects and thereby
creating a memory-leak.
The updateMonitor() method then uses the map to lazily initialize a new IncrementMonitor. Once the method is sure the
monitor exists, it updates it with the latest progress (indicated by the return value of read()). Listing 4 shows the code for
the lazy initialization and progress updates, as well as the full code for IncrementMonitor:
Listing 4. Lazy initialization of per-stream monitor

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (10 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

//From the aspect...


private void updateMonitor(JComponent component, InputStream is,
int amount){
IncrementMonitor monitor =
(IncrementMonitor)perStreamMonitor.get(is);
if(monitor == null){
monitor = initMonitor(is, component);
}
monitor.increment(amount);
}
private IncrementMonitor initMonitor(InputStream is,
JComponent component){
try {
int size = is.available();
IncrementMonitor monitor =
new IncrementMonitor(component, size);
perStreamMonitor.put(is, monitor);
return monitor;
} catch (Exception e) {
//...handle
}
}
}//...end aspect
public class IncrementMonitor extends ProgressMonitor{
private int counter;
public IncrementMonitor(Component component, int size){
super(component, "Some Title", null, 0, size);
}
public void increment(int amount){
counter += amount;
setProgress(counter);
}
}

Finally, the aspect needs to discard the monitor when the stream has been fully read. If you're thinking in aspects at the
moment, you'll recognize the opportunity. InputStream conveniently defines a close() method for the aspect to advise, as
shown here:

before(InputStream is):
call(public void InputStream+.close())
&& target(is)
{
System.out.println("Discarding monitor.");
perStreamMonitor.remove(is);
}

At this point, you've completed the exercise. If you're familiar with the implementation of InputStream, however, you'll have
spotted something I deliberately left out. The read() method (no parameters) must be handled differently from the other
readmethods because its return value is not the number of bytes read, but rather the next byte in the stream. The example
code that accompanies this article expands the aspect to deal with this constraint, but I urge you to visualize how you would
address this concern if you were writing the aspect before referring to the code.

Analysis of the AspectJ Decorator


Like Adapter, the two implementations of Decorator differ in localization. In the AspectJ version, the entire pattern sits
neatly in a single aspect. (I've excluded the IncrementMonitor helper class because it does not play a structural role in the
pattern.) In the Java language version, the base pattern implementation (leaving aside the client code) requires three
classes. What effects does this have?

Understanding: Because of the power of AspectJ's pointcut language, an aspect can affect multiple operations
with the same advice. In contrast, a decorator class must repeat the behavior at each operation. In part because of

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (11 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

this, Sun's implementation shows more than twice as many lines of code as the aspect implementation. I counted
approximately 110 lines for the ProgressMonitorInputStream and 40 for FilterInputStream (I'll leave out
InputStream since it could be a legitimate superclass absent the Decorator pattern). In contrast, the
MonitorFileReads aspect consumes 53 lines, and the IncrementMonitor helper class consumes 12. The line
ratio stands at 160 to 65, or about 2.4 to 1. Although lines-of-code (LOC) is a crude measure, in general shorter
code is clearer code.
Furthermore, if you are familiar with AOP, the AspectJ solution does not give you the sense that something special
is going on. The Java language solution requires several classes working carefully in concert, while the AspectJ
version looks as if it's doing what most aspects do: adding behavior to a set of join points through advice.
Finally, it's worth remembering that a frequent criticism of AOP is that you can "no longer tell what a module is
doing by reading the source." If you apply decorators to objects without the help of aspects, there's no sourcebased clue in either the client code (other than the wrapping location) or the decoration target (the
FileInputStream) that the object displays additional behavior. In contrast, if you examine the GUI from Listing 2 in
AJDT, you will see a friendly annotation on the line while (in.read(b) != -1) that indicates that the monitoring
aspect affects the read call. The combination of AspectJ and its development environment provides better
information in this case than the original implementation.

Reusing: Because decoration is built into the language, almost all aspects reuse this pattern. A more specific
reuse would be to make the monitoring aspect abstract and allow subaspects to specify a pointcut for monitored
operations. In this way, nearly any object could be decorated with monitoring -- without the preparation required by
the traditional implementation. (If you're wondering about abstract aspects, Part 2 of the article explains their use in
more detail.)
Maintaining: Adding a new decoration to an object requires no special effort. If the decoration target changes
(imagine a new type of read method), then you must (possibly) update the pointcuts to account for this. Having to
update a pointcut is burdensome, but the burden can be reduced by writing robust pointcuts that are likely to catch
new operations. (See the Resources for a link to a great blog entry on robust pointcuts.) In any case, updating a
pointcut seems less trouble than updating all the decorators as would be required for a similar change in the Javalanguage implementation.
Here's another interesting scenario (mentioned earlier in the Java language analysis): monitoring all file reads. With
an OO decorator, this means that every class that reads a stream must remember to wrap it in a
ProgressMonitorInputStream. In contrast, the MonitorFileReads aspect will monitor reads on any input stream
as long as they occur from within the control flow of a JComponent. Because ProgressMonitor only ever pops up
when the operation is taking longer than a preset threshold, this aspect could transparently ensure that users never
get annoyed at having to wait for a file read -- without the need for programmer vigilance.

Composing: Like the competing implementation, the AspectJ version allows for transparent composition of
multiple decorators with low effort.

As I've mentioned before, Decorator's chief trick (transparently adding behavior to an operation) is subsumed by the
AspectJ language. The only challenge for the AspectJ implementation is how to associate aspectual state (the updated
progress monitor) with a specific instance -- the example used a map to make this association. This need to handle the
association preserves Decorator as a pattern in AspectJ. Sometimes, when the decoration machinery already exists, it
seems easier to use a traditional Decorator -- especially because the pattern does not invade the decorated class.
However, if the decoration machinery does not exist, the flexibility and simplicity of the AspectJ implementation make a
better choice.

Conclusion to Part 1
I hope that this tour of two familiar patterns has helped illustrate aspect-oriented mechanisms in practice. As the
development community grapples with the ramifications of an emerging paradigm, it can be useful to apply the new
technology to old problems -- problems for which good solutions already exist. The exercise can provide a familiar vantage
from which to asses the new approach.
So how has it fared so far? While it's not a golden hammer, AspectJ has managed to secure some solid advantages when
used to implement traditional OO patterns. These advantages stem from AspectJ's ability to better handle crosscutting
concerns. By gathering the code for a pattern into a single aspect, AspectJ makes it easier to understand the pattern from
reading the code. Because pattern code does not show up in non-pattern classes (such as the wrapping locations required
http://www-128.ibm.com/developerworks/library/j-aopwork5/ (12 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

by Adapter and Decorator) these other classes are also easier to understand. The combination also makes it easier to
extend and maintain the system, and even to reuse the patterns elsewhere.
Adapter and Decorator represent medium-complexity patterns. In Part 2 of this article, I'll examine whether aspectorientation scales to more complex patterns. Specifically, Part 2 tackles Observer, a pattern that involves multiple roles and
dynamic relationships. Part 2 also explores aspect-oriented reuse -- the ability to define a pattern or protocol as an abstract
aspect and to apply it with an application-specific aspect.

Resources

Click the Code icon at the top or bottom of this article (or see Download) to download the source code discussed in
this article.
AOP@Work is a year-long series dedicated to helping you incorporate AOP into your day-to-day Java
programming. Don't miss a single article in the series. See the complete series listing.
If you need an introduction to AspectJ and AOP, check out the introductory article "Improve modularity with aspectoriented programming" (developerWorks, January 2002).
For more information on the AspectJ development environment (AJDT), take a look at and this offering from
members of the AJDT team: " Develop aspect-oriented Java applications with Eclipse and AJDT" (developerWorks,
September 2004).
The section on Decorator suggests that you take a look at the sources for java.io. Sun provides an
implementation: J2SE 1.4.2.
Learn more about the Gang of Four and their book at Hillside.net.
The Aspect-Oriented Design Pattern Implementations project has so far refactored 23 GoF patterns using AspectJ;
three of them are studied in this article.
Project authors Jan Hannemann and Gregor Kiczales have made reusable abstract aspects from 13 of the studied
patterns freely available under the Mozilla Public License.
For a more in-depth study, see Hannemann and Kiczales's "Design Pattern Implementation in Java
AspectJ" (OOPSLA, November 2002), which proposes that AspectJ implementations of the GoF design patterns
show modularity improvements in 17 of 23 cases.
Adrian Colyer's The Aspects Blog brings you up to the minute news from the AspectJ project combined with
penetrating design insights and practical applications of aspect technology. This entry discusses how to write
robust pointcut expressions .
The Portland Pattern Repository is an excellent resource for learning about patterns, as well as a great introduction
to the patterns community. It includes sections on the Adapter, Decorator, and Observer patterns.
Ramnivas Laddad's AspectJ in Action: Practical Aspect-Oriented Programming (Manning, 2003) includes several
forward-thinking patterns for AOP.
You may also want to check out these excellent titles written by contributors to the AOP@Work series:

Mastering AspectJ (Joseph D. Gradecki and Nicholas Lesiecki; John Wiley & Sons, 2003).
Eclipse AspectJ: Aspect-Oriented Programming with AspectJ and the Eclipse AspectJ Development Tools
(Adrian Colyer, Andy Clement, George Harley, Matthew Webster; Addison-Wesley Professional, 2004).

You'll find articles about every aspect of Java programming in the developerWorks Java technology zone.
Visit the Developer Bookstore for a comprehensive Listing of technical books, including hundreds of Java- related
titles.

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (13 of 14)5/19/2005 5:48:03 AM

AOP@Work: Enhance design patterns with AspectJ, Part 1

Also see the Java technology zone tutorials page for a complete Listing of free Java-focused tutorials from
developerWorks.

Download
Name

Size

Download method

j-aopwork56code.zip

142 KB

FTP

Information about download methods

About the author


Nicholas Lesiecki is a recognized expert on AOP in the Java language. In addition to coauthoring Mastering AspectJ (Wiley, 2003), Nick is a member of
AspectMentor, a consortium of experts in aspect-oriented software development. He has spoken about applying AspectJ to testing, design patterns, and realworld business problems in such venues as SD West, OOPSLA, AOSD, and the No Fluff Just Stuff symposium series. He currently serves Google as a
Software Engineer and Programming Instructor.

Rate this article


This content was helpful to me:

Strongly disagree (1)

Disagree (2)

Neutral (3)

Comments?

Submit feedback
developerWorks

> Java technology >

About IBM

Privacy

Contact

http://www-128.ibm.com/developerworks/library/j-aopwork5/ (14 of 14)5/19/2005 5:48:03 AM

Agree (4)

Strongly agree (5)

You might also like