Logic-based program transformation in symbiosis with Eclipse
Detecting aspect-specific code smells using Ekeko for AspectJ
1. Detecting aspect-specific code smells
using Ekeko for AspectJ
Coen De Roover Johan Fabry
Software Languages Lab Pleiad Lab - DCC
Vrije Universiteit Brussel University of Chile
2. Aspect-oriented programming
... modularizes cross-cutting concerns
aspect 1 aspect 3
aspect 2
Aspect
Weaver
core application functionality
woven output code
pointcut
specifies program points at which the aspect intervenes
advice
behavior to invoke at points selected by a pointcut
3. Code smells in aspect-oriented programs
2.3 Detecting Lazy Aspects
This bad smell, initially defined in [M.P. Monteiro, 2005], occurs if an aspect has
... symptoms of suboptimal implementation
few responsibilities, and its elimination could result in benefits during mainte-
nance activities. Sometimes, this responsibility reduction is related to previous
refactoring or to unexpected changes in requirements (planned changes that did
not occur, for instance).
e.g., [Piveta07] Definition 03 Consider an aspect α. The crosscutting members of α are the
collection of all advice, pointcuts, declare constructions and inter type declara-
large aspects tions directly defined in α. Consider η as the number of crosscutting members of
α. An aspect is considered a lazy one whenever the predicate η == 0 holds. The
advices with anonymous pointcuts
function could be defined as: f (α) = η == 0
To detect lazy aspects, a similar approach to the Large Aspect bad smell is
lazy aspects taken. The LazyAspectASTVisitor creates bad smell events whenever an aspect
without crosscutting members is found (see Listing 4).
1 public c l a s s LazyAspectASTVisitor extends
BadSmellsASTVisitor {
2 public void e n d V i s i t ( T y p e D e c l a r a t i o n node ) {
3 super . e n d V i s i t ( node ) ;
4 i f ( ( ( A j T y p e D e c l a r a t i o n ) node ) . i s A s p e c t ( ) )
5 i f ( getNumberOfMembers ( ) == 0 ) {
6 BadSmellsEvent e v e n t = new BadSmellsEvent ( ) ;
7 e v e n t . setType ( ” Lazy Aspect ” ) ;
8 ...
9 }
10 }
11 } but:
Listing 4: AST visitor responsible for the detection of the Lazy Aspect bad smell
extrapolated from OO smells
rather informal specification
4. Assumption-based code smells
... aspect/aspect aspect/base assumptions
Aspect–Aspect Coordination
Inter-Aspect Inter-Advice Inter-Process
Deployment ITDs Super-Aspect Wormhole Advice Execution
Structure Sequence
Sub-Aspect
Precedence
Aspect Structure
[Zschaler11] Assumptions
Aspect–Base Coordination
Synchronisation Architecture Coding Patterns
Managed Monitor Communication Data Code Code
by Context Sharing Advised Called
Figure 1: Top-level aspect assumption categories identified
assumption: Examples. The Glassbox aspect JxtaSocketMonitor assumes
to have precedence over its super-aspect AbstractMonitor.
thread t. Conversely, let ef (a, t) indicate that ad
executing in thread t.3 Then, we might formal
This is the default semantics of AspectJ. However, an assumption that advice a1 ∈ A assumes previous executio
remains that this is not changed by any declare precedence
behaviour A1 introduces or to introduce base behaviour that A1 ψ aspect 1 .G¬es (a1 , t )U∃t2 .ef (a2 , t2 ).4
among other things, this A ⇒ ∀tassumes that 1the Observer-Pattern
can then modify. If A1 requires Aanywhere in the code.
clauses 2 to be deployed because it uses aspect is only woven into the system for data updates (and not, for as
Examples. For example, MobileMedia has an
inter-type definitions (ITDs) defined in A2 , this may be influenced by declare prece- creation).
Discussion. Precedence is classified with example, for data MusicAndVideo, which is deployed when a
the other ITD assumptionsdence clauses directly referencing a set of aspects, but also quite
below. Beyond the general case, we have identified a specifictwo pieces o
tures are selected. This provides variation,
tool support: warn when advice precedence DAG is not completely connected
indirectly. For example, AbstractMonitor defines an interface defines a marker interface that isother reacting to
A special case is when an aspect A1 has been introduced to re-
between two other aspects aspect A3
where one aspect forming some setup code, the then used by
solve a feature interactionLowerPrecedence. AnyA2 and implementing this aspect in a declare parents clause. In thisClearly, ther
another interface items installed by the first advice. case, the
(or more). In this case, will automatically receive lower precedence thansecond aspect assumes deployment of the first, so that the semantics
there will be an inclusion assumption AbstractMo- here that the first advice has run before the seco
warn about aspects that override implicit precedence
ψA1 ⇒ d(A2 ) ∧ d(A3 ).
nitor. Discussion. If broken, this type of assumptio
of the marker interface are operationalised.
However, AspectJ’s declare precedence clause can also pected behaviour or errors at runtime. For ex
Examples. MobileMedia uses aspects to configure different prod- For example, Glassbox defines interface MonitoredType.
be used to make precedence assumptions explicit. Then, if they are bileMedia case, if the setup code were not to be
ucts of a product line. For example, deploying PhotoAndMu- has been done for the a top-level interface, but is documented touser, bec
continuously check assumptions made explicit in code
violated, ajc will produce an error. This
sicAspect implies features for both photo and music manage-
This is defined as feature would not be accessible to the “start
[the] agent when loading any such type. Should be added to any
5. Eclipse plugin
causally connected
Ekeko
applications
program querying
program transformation
corpus mining
meta-programming library
for Clojure’s core.logic
logic meta-programming
specify code characteristics declaratively, leave search to logic engine
applicative meta-programming
script queries over workspace
manipulate workspace
7. Applicative logic meta-programming
... core.logic in a nutshell
embedding of logic programming
port of Kanren [Friedman, Kiselyov, Bird] to Clojure by David Nolen
no operational impurities (e.g., cut), yet high performance
features tabling, extensible constraints, extensible unification protocols
core.logic
logic goals
functions that take a substitution
either return a possibly infinite stream of substitutions (success) or nil (failure)
constructors:
always success: s#, always failure: f#, success if arguments unify: ==
composing goals
introduces lexically scoped variables
chains goals together abstraction
(fresh
[?x
?y] (defn
g
[?y]
(fresh
[?x
?y]
(conde
(fresh
[]
(==
?x
?y)
[(==
?x
1)
..]
(==
?y
5)))
(==
?x
5)))
[(==
?x
5)
..]))
(fresh
[?x]
interleaves substitutions from goals
(g
?x))
8. Applicative logic meta-programming
... using relations provided by the Ekeko library
syntactic
concern
characteristics { structural
control flow
data flow
JDT DOM
derived
from
{ JDT Model
control flow graph
SOOT data flow analyses
AspectJ weaver
(defn
aspect-declaredsuper+
"Relation between an aspect and one of its declared ancestors.”
[?aspect ?ancestor]
(conde
[(aspect-declaredsuper ?aspect ?ancestor) ]
[(fresh [?super]
(aspect-declaredsuper ?aspect ?super)
(aspect-declaredsuper+ ?super ?ancestor))]))
9. Example queries
... using Ekeko for AspectJ
(ekeko* [?advice1 ?advice2 ?shadow] two advices operating on the
(advice-shadow ?advice1 ?shadow) same join point shadow
(advice-shadow ?advice2 ?shadow)
(!= ?advice1 ?advice2))
(ekeko* [?declaringaspect ?intertype ?member ?targettype]
(aspect-intertype ?declaringaspect ?intertype)
(intertype-member-type ?intertype ?member ?targettype)
(aspect ?targettype))
aspect adding a member to another
aspect through an intertype declaration
advice operating on a join point shadow
stemming from an intertype declaration
(ekeko* [?advice ?shadow ?intertype]
(intertype-element ?intertype ?shadow)
(advice-shadow ?advice ?shadow))
10. Code smells
... related to precedence graph
(defn
incomplete-precedence precedence DAG is
not fully connected
[?first ?second]
(all
(aspect ?first) an aspect may assume default
(aspect ?second) precedence is never changed
(!= ?first ?second)
(fails (aspect-dominates-aspect ?first ?second))
(fails (aspect-dominates-aspect ?second ?first))))
(defn
overriden-implicit-precedence aspect overrides implicit
precedence
[?first ?second]
(all
(aspect-dominates-aspect ?second ?first)
(aspect-dominates-aspect-implicitly+ ?first ?second)))
inverse assumption made explicit
11. Code smells
... related to aspect hierarchy
(defn
pointcut concretizing
pointcut-concretizedby abstract pointcut from
[?abstractpc ?concretepc] super aspect
(fresh [?abaspect ?concaspect ?name]
(aspect-super+ ?concaspect ?abaspect)
(aspect-pointcutdefinition ?abaspect ?abstractpc)
(aspect-pointcutdefinition ?concaspect ?concretepc)
(pointcut-name ?abstractpc ?name)
(pointcut-name ?concretepc ?name)))
aspect introducing pointcut assumes it
is not already defined unless behavior of
super does not need to be maintained
(defn
abstractpointcut-concretized-reconcretized pointcut
[?abpointcut ?concpointcut1 ?concpointcut2] concretized
twice
(all
(pointcut-concretizedby ?abpointcut ?concpointcut1)
(pointcut-concretizedby ?concpointcut1 ?concpointcut2)))
12. Code smells
... related to intertype declarations
(defn
modifies-aspect
[?modifier ?modified]
(fresh [?advice ?shadow]
(aspect-advice ?modifier ?advice)
aspect modifies (advice-shadow ?advice ?shadow)
another aspect (shadow-enclosingtypedeclaration ?shadow ?modified)
(aspect ?modified)))
(defn an intertype declaration introduces
a method that is never called
intertypemethod-unused
[?itmethod]
(fresh [?caller]
(intertypemethod ?itmethod)
(fails
(soot-method-called-by-method ?itmethod ?caller)))))
13. Code smells
... related to behavioral patterns
public aspect WormholeAspect {
pointcut entry(int save):
execution(* BaseClass.method1(int)) && args(save);
pointcut exit() :
execution(* BaseClass.method2());
int store;
before(int savedarg) : entry (savedarg) {
this.store = savedarg;
}
before() : exit() {
System.out.println("Wormholed value is: "+ store);
}
} assumes it is the
wormholed value
15. Conclusions
logic-based specifications
Ekeko provides actual tool support
of smells related to implicit aspect assumptions
moving from structurally to behaviorally characterized
Ongoing work
designing annotation library for making assumptions explicit
continuously cross-check explicit and derived assumptions
empirical study
script Ekeko against AspectJ corpus
https://github.com/cderoove/damp.ekeko [.aspectj]