Content uploaded by Vinicius Cardoso Garcia
Author content
All content in this area was uploaded by Vinicius Cardoso Garcia
Content may be subject to copyright.
Available via license: CC BY 3.0
Content may be subject to copyright.
c
Copyright 2004, Vinicius Cardoso Garcia, Eduardo Kessler Piveta, Daniel Lucr´
edio,
Alexandre Alvaro, Eduardo Santana de Almeida, Antonio Francisco do Prado, Luiz Car-
los Zancanella. Permission is granted to copy for the SugarLoafPLoP 2004 conference.
All other rights reserved.
Manipulating Crosscutting Concerns
Vinicius Cardoso Garcia1∗
, Eduardo Kessler Piveta2, Daniel Lucr´
edio1†,
Alexandre Alvaro3, Eduardo Santana de Almeida3,
Antonio Francisco do Prado1, Luiz Carlos Zancanella 2
1GOES – Software Engineering Group
Federal University of S˜
ao Carlos, Department of Computer Science
S˜
ao Carlos, SP, Brazil
(vinicius, lucredio, prado)@dc.ufscar.br
2Federal University of Santa Catarina, CTC – Technological Center
Florian´
opolis, SC, Brazil
(kessler, zancanella)@inf.ufsc.br
3C.E.S.A.R. – Recife Center for Advanced Studies and Systems
Federal University of Pernambuco, Informatic Center
Recife, PE, Brazil
(aa2, esa2)@cin.ufpe.br
Abstract. The patterns in this paper describe how to extract crosscutting con-
cerns when developing systems.
Introduction
When using an object-oriented methodology and decomposing a system into a set of
individual classes and objects, there are some functionalities that are spread over several
classes. Figure 1 illustrates this scenario.
Figure 1: Crosscutting Concern tangled in the class
Code scattering and code tangling are problems that affect applications in a sys-
tematic way. They decrease maintainability, flexibility and reuse, mixing business code
∗Supported by Fundac¸˜
ao de Amparo `
a Pesquisa do Estado da Bahia (FAPESB) - Brazil
†Supported by Fundac¸˜
ao de Amparo `
a Pesquisa do Estado de S˜
ao Paulo (FAPESP) - Brazil
with code that is related to non-functional requirements, such as exception handling and
concurrency control, among others.
After the crosscutting concerns are identified, the extraction should be planned
through well defined techniques. The problem is how to extract concerns that are tan-
gled within the application code and spread over several classes. A solution is to use
Aspect-Oriented Programming [Kiczales et al., 1997], which allows to separate differ-
ent concerns into separate units. To extract these concerns from object-oriented systems
into aspects, it is possible to use refactorings [Fowler et al., 1999], adapted to the aspect-
oriented paradigm.
Consider the following source code:
import java.lang.reflect.*;
public class ShoppingCart {
private List items = new Vector();
public void addItem(Item item) {
System.out.println("Log:"+this.getClass().getName());
items.add(item);
}
public void removeItem(Item item) {
System.out.println("Log:"+this.getClass().getName());
items.remove(item);
}
public void empty() {
System.out.println("Log:"+this.getClass().getName());
items.clear();
}
}
This code mixes business logic with logging. The logging code (shaded) must be
extracted to an aspect. To perform this, the patterns described in this paper could be used,
allowing to move fields, pieces of code and entire methods that are related to logging into
the new aspect. Figure 2 shows the inter-relationship among the patterns. The arrows
inform which refactoring are commonly used given the resultant context of the patterns
application. In some cases, the patterns point at the inverse pattern. The patterns in gray
are not described in this work.
Figure 2: Patterns to Extract Crosscutting Concerns
The AspectJ language was used in the examples to demonstrate the use of the
patterns. The format used to describe the patterns in this paper is the same used in refac-
torings [Fowler et al., 1999].
EXTRACT FIELD TO ASPECT
Figure 3: Extract Field to Aspect
A class has a field that is related to a crosscutting concern that is implemented or
is being extracted to an aspect.
import java.lang.reflect.*;
public class ShoppingCart {
private List items = new Vector();
private java.io.PrintWriter logWriter = System.err;
public void addItem(Item item) {
logWriter.println("Log:"+this.getClass().getName());
items.add(item);
}
public void removeItem(Item item) {
logWriter.println("Log:"+this.getClass().getName());
items.remove(item);
}
public void empty() {
logWriter.println("Log:"+this.getClass().getName());
items.clear();
}
}
The solution is to move the field to the aspect that implements the concern, as an
introduction declaration.
Motivation
By extracting the field into an aspect, the code tangling problem is reduced, since the
aspect will contain all the fields related to a single concern, and no field related to that
concern is located outside the aspect.
Mechanisms
•If the field is defined as being public, consider the use of Encapsulate Field
([Fowler et al., 1999], p.206) before this pattern is applied.
•Move the field declaration to the aspect, including the initial value declaration, if
there is one. This must be done in accordance to the introduction syntax of the
aspect language used.
•Analyze if there is the need to declare namespace statements.
•Modify the field visibility to public. The visibility could be decreased after the
whole pattern is applied. If there is still the need to keep the code related to
the field in the class, consider using Self Encapsulate Field ([Fowler et al., 1999],
p.146).
•Check all pointcuts containing “within()” declarations that must be updated after
the application of this pattern.
•Compile and test.
You could use EXTRACT FIELD TO ASPECT to extract fields related to the
logging concern to the aspect. After the pattern is applied:
public aspect LoggingAspect {
private java.io.PrintWriter ShoppingCart.logWriter = System.err;
pointcut loggedMethods(ShoppingCart shoppingcart): this(shoppingcart)
&& (execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
logWriter.println("Log:"+shoppingcart.getClass().getName());
}
}
. .. after the EXTRACT FIELD TO ASPECT is applied, some methods that refer
to those fields should also be moved to the aspect, since they probably refer to the same
concern that is being extracted. To extract those methods, as well as other methods that
refer to this concern, use EXTRACT METHOD TO ASPECT.
EXTRACT METHOD TO ASPECT
Figure 4: Extract Method to Aspect
There are methods in the class that relate to a crosscutting concern implemented
as an aspect or that is being extracted to one. The problem is how to extract the method
to the aspect, since the method has its own visibility, return value and is part of the class
context.
import java.lang.reflect.*;
public class ShoppingCart {
private List items = new Vector();
private void addLogMessage(String message) {
System.out.println("Log "+(logNumber++)+":"+message);
}
public void addItem(Item item) {
addLogMessage(this.getClass().getName());
items.add(item);
}
public void removeItem(Item item) {
addLogMessage(this.getClass().getName());
items.remove(item);
}
public void empty() {
addLogMessage(this.getClass().getName());
items.clear();
}
}
The solution is to move the method to the aspect that implements the crosscutting
concern, as an introduction declaration.
Motivation
A method that refers to a particular concern should be located inside the aspect that im-
plements this concern, in order to reduce the code tangling and spreading.
Mechanisms
•Move the method declaration from the class to the aspect. This must be performed
in accordance with the introduction syntax of the aspect language used.
•Analyze if there are namespaces declarations that must be inserted.
•Check all pointcuts with the declaration “within()” that should be updated after
the application of this pattern.
•Compile and test.
You could use EXTRACT METHOD TO ASPECT to extract method related to
the logging concern to the aspect. After it is applied:
public aspect LoggingAspect {
private void ShoppingCart.addLogMessage(String message) {
System.out.println("Log :"+message);
}
pointcut loggedMethods(ShoppingCart shoppingcart): this(shoppingcart)
&& (execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
addLogMessage(shoppingcart.getClass().getName());
}
}
...after the EXTRACT METHOD TO ASPECT is applied, there are no meth-
ods that refer to the concern being extracted. However, calls to these methods remain
located in other methods that were not extracted to the aspect. There could also be pieces
of code that are related to this concern, but are not separated as entire methods. To extract
these method calls and other pieces of code, use EXTRACT CODE TO ADVICE.
EXTRACT CODE TO ADVICE
Figure 5: Extract Code to Advice
Some piece of code is related to a concern that could be implemented as an aspect.
This code is not separated in a single method, but mixed with other codes.
Extract the code to an advice
Motivation
Method calls that appear in several classes are usually subject to this pattern. The correct
separation of concerns could improve software maintainability and reuse.
Mechanisms
•Create an empty advice.
•Move the code that is being extracted into the advice body
•Add code to implement the advice context
•Substitute references to this (the actual object) by the variable captured in the
join-point context.
•Analyze the extracted code, searching references to local variables in the method
scope, including parameters and local variables. Any declarations to temporary
variables, used only in the extracted code, could be substituted in the advice body.
•Compile the code and test.
Example
You could use this pattern to extract code related to the execution of addItem to the aspect.
After the pattern is applied:
import java.lang.reflect.*;
public class ShoppingCart {
private List items = new Vector();
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
System.out.println("Log:"+this.getClass().getName());
items.remove(item);
}
public void empty() {
System.out.println("Log:"+this.getClass().getName());
items.clear();
}
}
The code related to the logging was extracted to the aspect Foo:
public aspect Foo {
before(ShoppingCart shoppingcart): this(shoppingcart) &&
(execution(void ShoppingCart.addItem(..))) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
Note that the context regarding the variable this has also moved to the aspect.
...after applying this pattern once, there are still calls to methods that perform
logging. So, execute EXTRACT CODE TO ADVICE in the other affected methods in
the class. Then, the class becomes like this:
import java.lang.reflect.*;
public class ShoppingCart {
private List items = new Vector();
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
items.remove(item);
}
public void empty() {
items.clear();
}
}
And the aspect:
public aspect Foo {
before(ShoppingCart shoppingcart): this(shoppingcart) &&
(execution(void ShoppingCart.addItem(..)))
|| (execution(void ShoppingCart.removeItem(..)))
|| (execution(void ShoppingCart.empty(..))) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
...after the EXTRACT CODE TO ADVICE is applied to several methods, the
join-points declaration grows and becomes highly coupled with the advice body. In order
to improve clarity and make the coupling softer, EXTRACT POINTCUT DEFINITION
could be used.
EXTRACT POINTCUT DEFINITION
Figure 6: Extract Pointcut Definition
The join-points definition is coupled with the advice code.
Separate the join-points definition into a pointcut.
Motivation
You could define a separated pointcut, defining join-points and the correct context. The
separation between pointcut definitions and advices makes the code more readable and
flexible, since modifications could be performed in a single place. Also, the code becomes
more reusable, since a single pointcut definition could be used by several advices.
Mechanisms
•Create a pointcut that captures the appropriate join-points. If the pointcut already
exists, extend it to include the related join-point(s) to the extracted code.
•Ensure that the pointcut captures the entire context that is required by the code
snippet. Check if the extracted code refers to this or super declarations. The
most used types of predicates defined in the pointcuts use references to the object
receiving a message and calls to a specific method, or a reference to the actual
object combined with method execution, field read and write operations etc.
•Compile the code and test.
Example
After the pointcut definition is extracted:
public aspect Foo {
pointcut test(ShoppingCart shoppingcart): this(shoppingcart) &&
(execution(void ShoppingCart.addItem(..)))
|| (execution(void ShoppingCart.removeItem(..)))
|| (execution(void ShoppingCart.empty(..)))
);
before(ShoppingCart shoppingcart): test(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
...after applying EXTRACT POINTCUT DEFINITION, the join-points declaration
could became verbose. An equivalent predicate could be used instead of individual join-
points. To perform this, use COLLAPSE POINTCUT DEFINITION
COLLAPSE POINTCUT DEFINITION
Figure 7: Collapse Pointcut Definition
The pointcut declaration could became verbose.
An equivalent predicate could be used instead of individual join-points.
Motivation
When the number of affected points increase, the maintainability of the pointcut become
harder. The definition grows as new classes and methods are created and references are
added to the aspect. Regular expressions are used to express collections of join-points.
Mechanisms
•Check how many determinable join-points are currently affected by the pointcut
•Convert the join-point declaration into a regular expression.
•Compile the code and test.
•Verify if the number of affected points is the same as previously measured
Example
After the COLLAPSE POINTCUT DEFINITION was applied:
public aspect Foo {
pointcut test(ShoppingCart shoppingcart): this(shoppingcart) &&
(execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): test(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
...after collapsing the definition, we could realize that the pointcut name does not help
us to identify what it is all about. So, to provide a meaningful name, apply RENAME
POINTCUT.
RENAME POINTCUT
Figure 8: Rename Pointcut
The name of a pointcut does not reveal its purpose.
Change the name of the pointcut
Motivation
Names are one of the best mechanisms to express the intent of a feature. If you have
odd names to classes, methods and aspects, your code becomes harder to understand and
maintain. Provide good names to improve code quality.
Mechanisms
•Create a new pointcut with the given name.
•Copy the declaration from the old pointcut to the new one.
•Change the old pointcut to point to the new one (if you have a few references you
could skip this step)
•Compile and test
•Change the references to the old pointcut in advices and other pointcuts to the new
pointcut
•Compile and test for each change
•Remove the old pointcut declaration
•Compile and test
Example
After renaming the pointcut, we have:
public aspect Foo {
pointcut loggedMethods (ShoppingCart shoppingcart):
this(shoppingcart) && (execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
And so on, after extracting the profiling concern to the Foo aspect, we realize that this
aspect should be renamed to a better name using RENAME ASPECT.
RENAME ASPECT
The name of an aspect does not reveal its purpose.
Change the name of the aspect
Figure 9: Rename Aspect
Motivation
A good practice is to name classes, aspects, methods ..., in order to improve code read-
ability. If you have to look at the source code of a class or a method to imagine what the
feature is responsible for, this feature is a candidate to this pattern.
Mechanics
•Check to see whether the aspect name is used by a super-aspect or a sub-aspect.
If it is, rename the references in the sub and super-classes
•Change the name of the aspect
•Find all references to the old aspect name and change them to the new name.
•Compile and test
After renaming the aspect:
public aspect LoggingAspect {
pointcut loggedMethods(ShoppingCart shoppingcart): this(shoppingcart)
&& (execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
...after the aspect is extracted, with its fields, methods and advices, and properly named,
you could separate some features, such as the pointcut definition, from the implementa-
tion, using abstract pointcuts and abstract aspects, in order to increase reusability, flexi-
bility and readability.
PULL UP ADVICE/POINTCUT
Figure 10: Pull Up Advice/Pointcut
An aspect have functionalities that could be used or are effectively being used by
several related aspects.
Move these functionalities to a super-aspect.
Motivation
Code duplication is one of the responsible for the high costs on maintainability. The use
of inheritance could help on avoiding code duplication.
Mechanisms
•Inspect the pointcut/advice to ensure that they are identical
•Create a new pointcut in the super-aspect with the same signature of those in the
sub-aspects and declare it to be abstract.
•Create a new advice in the super-aspect and copy the body of the old advice to the
advice defined in the super-class
•Remove the old advice
•Compile and test.
Example
After PULL UP ADVICE/POINTCUT, we have:
abstract aspect AbstractLoggingAspect {
abstract pointcut loggedMethods(ShoppingCart shoppingcart);
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
public aspect LoggingAspect extends AbstractLoggingAspect {
pointcut loggedMethods(ShoppingCart shoppingcart): this(shoppingcart)
&& (execution(void ShoppingCart.*(..)));
}
...sometimes, separating features throughout aspects hierarchy is not good. In this case,
the opposite process can be performed using COLLAPSE ASPECT HIERARCHY.
COLLAPSE ASPECT HIERARCHY
Figure 11: Collapse Aspect Hierarchy
You have an aspect and a super-aspect that are quite similar, or the cost of having
a super-aspect is dubious.
Merge the aspect and its super-aspect together
Motivation
To separate features into aspects and super-aspects is useful when you want to make
these features available to other aspects. However, this separation has a cost, either in
readability and maintainability, since there are two modular units to be considered: the
super-aspect and the sub-aspect. If these costs are not compensated by gains in reusability,
such as when a single sub-aspect reuses the features in a super-aspect, it is better if these
features are grouped into a single modular unit.
Mechanisms
•Choose which aspect is going to be removed: the aspect or its super-aspect
•Use PULL UP ADVICE/POINTCUT, PULL UP METHOD and PULL UP FIELD
or PUSH DOWN ADVICE/POINTCUT (those are not described here), PUSH
DOWN METHOD and PUSH DOWN FIELD
•Compile and test in each PUSH/PULL operation
•Modify references to the class that will be removed to use the merged aspect. This
affects variable declarations, parameters and constructors.
•Remove the empty aspect
•Compile and test
After COLLAPSE ASPECT HIERARCHY, we have:
public aspect LoggingAspect {
pointcut loggedMethods(ShoppingCart shoppingcart):this(shoppingcart)
&& (execution(void ShoppingCart.*(..)));
before(ShoppingCart shoppingcart): loggedMethods(shoppingcart) {
System.out.println("Log:"+shoppingcart.getClass().getName());
}
}
...after collapsing the aspect hierarchy, we could realize that the advice is just as clear as
the related pointcut’s name. So, to provide a meaningful name, apply INLINE POINT-
CUT DEFINITION.
INLINE POINTCUT DEFINITION
Figure 12: Inline Pointcut Definition
Sometimes, a pointcut is used into one advice only and its quite obvious. There is
no reason to separate the pointcut definition from the advice.
Put the predicate containing the affected join-points in the advice definition
Motivation
To maintain a pointcut definition that is used by a single advice results in unnecessary
extra code. This reduces the readability and maintainability.
Mechanisms
•Check if the pointcut/advice is not overridden in the sub-classes and it is not ab-
stract
•Find all references to the pointcut
•Replace the references with the pointcut definition
•Remove the pointcut predicate and make the pointcut abstract
•Compile and test
•Remove the pointcut
Example
After INLINE POINTCUT DEFINITION, we have:
public aspect Foo {
before(ShoppingCart shoppingcart): this(shoppingcart) &&
(execution(void ShoppingCart.*(..))) {
System.out.println("LOG:"+shoppingcart.getClass().getName());
}
}
Acknowledgements
We shall not forget to thanks Jim Coplien. He made an outstanding work, guiding us and
making us understand what patterns are really about.
References
Fowler, M., Beck, K., Brant, J., Opdyke, W., and Roberts, D. (1999). Refactoring: im-
proving the design of existing code. Object Technology Series. Addison-Wesley.
Kiczales, G., Lamping, J., Mendhekar, A., Maeda, C., Lopes, C., Loingtier, J.-M., and
Irwin, J. (1997). Aspect-Oriented Programming. In Proceedings of the 11st Euro-
pean Conference Object-Oriented Programming (ECOOP’97), volume 1241 of LNCS,
pages 220–242. Springer Verlag.