Untangle Your Code with Aspect-Oriented Programming (AOP
Download
Report
Transcript Untangle Your Code with Aspect-Oriented Programming (AOP
Untangle Your Code with Aspect-Oriented
Programming (AOP): Part One
The Technical Resource Connection, Inc.
Frank Sauer
Associate, TRC
Agenda
Limitations of object-oriented programming
What is Aspect-Oriented Programming?
AspectJ
Patterns as reusable components
Transactional Java Objects
7/17/2015
© 2002 The Technical Resource Connection, Inc.
2
Clay or Gold?
“At present software is like Clay: it is soft and malleable early in
its lifetime, but eventually it hardens and becomes brittle. At that
point, it is possible to add new bumps to it, but its fundamental
shape is fixed, and it can no longer adapt adequately to the
constant evolutionary pressures of our ever- changing world.”
7/17/2015
© 2002 The Technical Resource Connection, Inc.
3
Clay or Gold?
“… produce software more like Gold –
malleable and flexible for life…”
(morphogenic software)
Harold Ossher and Perit Tarr, “Using multidimensional separation of concerns to
(re)shape evolving software”, Communications of the ACM, October 2001
7/17/2015
© 2002 The Technical Resource Connection, Inc.
4
Limitations of OOP
Object-oriented programming has matured to the point
we are now beginning to see its limitations.
Many requirements do not neatly decompose into
behaviors centered on a single locus.
The tyranny of the dominant decomposition: Every OO
decomposition results in cross-cutting concerns.
(Tarr 99)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
5
Cross-Cutting Concerns Visualized: Logging in Tomcat
(From AspectJ tutorial)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
6
Example: Tracing
class TraceSupport {
static int TRACELEVEL = 0;
static protected PrintStream stream = null;
static protected int callDepth = -1;
TraceSupport
static void init(PrintStream _s) {stream=_s;}
static void traceEntry(String str) {
if (TRACELEVEL == 0) return;
callDepth++;
printEntering(str);
}
static void traceExit(String str) {
if (TRACELEVEL == 0) return;
callDepth--;
printExiting(str);
}
class Point {
}
void set(int x, int y) {
TraceSupport.traceEntry(“Point.set”);
_x = x; _y = y;
TraceSupport.traceExit(“Point.set”);
}
}
7/17/2015
Consistent trace
form but using it
is cross-cutting...
© 2002 The Technical Resource Connection, Inc.
7
Other Cross-Cutting Concerns
Systemic
– security (authorization and auditing)
– logging and debugging
– synchronization and transactions
– persistence and many more
Functional
– business rules and constraints
– traversal of complex object graphs
– accounting mechanisms (timing and billing)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
8
The Cost of Tangled Code
Redundant code
– same or similar fragment of code in many places
Difficult to reason about
– non-explicit structure
– the big picture of the tangling isn’t clear
Difficult to change
– have to find all the code involved
– and be sure to change it consistently
– and be sure not to break it by accident
7/17/2015
© 2002 The Technical Resource Connection, Inc.
9
Aspect-Oriented Programming
AOP attempts to realize cross-cutting concerns as first-class
elements and eject them from the object structure into a new,
previously inaccessible, dimension of software development.
AOP encapsulates behavior that OOP would scatter throughout
the code by extracting cross-cutting concerns into a single
textual structure called an aspect.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
10
AOP: Opening a New Dimension in Software Development
Object
decomposition
is flatland
A cross-cutting concern is scattered
because it is realized in the wrong
dimension!
concerns
7/17/2015
© 2002 The Technical Resource Connection, Inc.
11
AOP: Opening a New Dimension in Software Development
Object
decomposition
is flatland
A cross-cutting concern is scattered
because it is realized in the wrong
dimension!
concerns
7/17/2015
© 2002 The Technical Resource Connection, Inc.
12
AOP: Opening a New Dimension in Software Development
Object
decomposition
is flatland
aspect
Aspects are
orthogonal to the
primary decomposition
concerns
7/17/2015
© 2002 The Technical Resource Connection, Inc.
13
Expected Benefits of AOP
Good modularity, even for crosscutting concerns
– less tangled code
– more natural code
– shorter code
– easier maintenance and evolution
easier to reason about, debug, change
– more reusable
library aspects
plug and play aspects when appropriate
7/17/2015
© 2002 The Technical Resource Connection, Inc.
14
Impact of AOP
AOP done right will not only clean up code, but will impact the
entire software development process as well. In fact, MIT
Technology Review lists AOP as one of the top 10 emerging
technologies that will change the world and names it in one
breath with brain-machine interfaces, flexible transistors, and
microphotonics.
–(MIT Technology Review, January 2001)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
15
The Four Ingredients of AOP
1. Joinpoint model: common frame of reference to define the
structure of cross-cutting concerns
2. Means to identify joinpoints
3. Means to influence the behavior at joinpoints
4. Means to weave everything together into a functional system
7/17/2015
© 2002 The Technical Resource Connection, Inc.
16
AspectJ
Java language extension for AOP developed at Xerox PARC
out of work on reflection and metaobject protocols
ajc compiler compiles Java and weaves aspects into classes
(ingredient 4)
open source!
http://www.aspectj.org
7/17/2015
© 2002 The Technical Resource Connection, Inc.
17
AspectJ Terminology
Joinpoint (Ingredient 1):
Any well-defined point of execution in a Java program such as
method calls, field accesses, and object construction
method call
join point
An
Object
int foo
Field access
join point
dispatch
set get
method
execution
join point
7/17/2015
© 2002 The Technical Resource Connection, Inc.
18
AspectJ Terminology
Pointcut (Ingredient 2):
Predicate on joinpoints selecting a collection of joinpoints.
Example:
call(public * com.trcinc..*.*.do*(..));
This pointcut matches any method call to public methods in any class in any
com.trcinc. subpackage whose name starts with ‘do’ with any number or type of
arguments and any return type
7/17/2015
© 2002 The Technical Resource Connection, Inc.
19
More on Pointcuts
Pointcuts can be composed as boolean expressions with &&, ||
and !
Pointcuts can be named
Pointcuts can have arguments (next slide)
Example named pointcut:
pointcut move():
call(Point.setX(..)) ||
call(Point.setY(..)) ||
call(Line.setP1(..)) ||
call(Line.setP2(..));
7/17/2015
© 2002 The Technical Resource Connection, Inc.
20
Pointcut Arguments
Example:
pointcut move(Object mover, Shape shape):
this(mover) && target(shape) &&
(call(Point.setX(..)) ||
call(Point.setY(..)) ||
call(Line.setP1(..)) ||
call(Line.setP2(..))
);
this(mover) binds mover to the object making the call. target(shape) binds shape to the
object being moved.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
21
Pointcuts Using Other Pointcuts
Dynamic pointcuts can further constrain other pointcuts:
pointcut toplevelMove():
move() && !cflowbelow(move())
Read as: A toplevel move is any move unless we are already in the process of moving.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
22
AspectJ Terminology
Advice :
Piece of code that attaches to a pointcut and thus injects
behavior at all joinpoints selected by that pointcut (Ingredient
3). This code executes before, after, or around a pointcut.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
23
Example After Advice
Update a display after any move of a shape:
after(): move() {
display.update();
}
after advice runs
“on the way back out”
move()
or with parameters:
shape
mover
after(Object mover, Shape shape): move(mover, shape)
{
display.update(mover, shape);
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
24
After Advice Variations
“after returning” only runs when joinpoint returned “normally”
“after throwing” runs when joinpoint threw an exception
You have access to the return value:
pointcut factoryMethod(Client c):
this( c ) && call(Shape Shape.make*(..));
after(Client c) returning(Shape s): factoryMethod(c) {
s.setColor(c.getColorFor(s));
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
25
Example Before Advice
Keep track of changes in transactional objects:
pointcut dirty(Persistent o): this(o) && set(* *.*);
before(Persistent o): dirty(o) {
String name = thisJoinPoint.getSignature().getName();
Transaction.getCurrent().setModified(o,name);
}
New pseudo variable (like this)
that always has information about
the current joinpoint
7/17/2015
© 2002 The Technical Resource Connection, Inc.
26
Example Around Advice
An around advice executes instead of the joinpoint and has
control over the continuation of the original code.
For example, enforce constraints on an argument:
void around(Point p, int newX):
call(void Point.setX(int)) && target(p) && args(newX) {
proceed(p, clip(newX, MIN_X, MAX_X));
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
27
AspectJ Terminology
aspect :
A modular unit of cross-cutting behavior. Very much like a class,
can have methods, fields, initializers, pointcuts and advices.
They can be abstract, inherit from classes and abstract aspects
and implement interfaces.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
28
The Hello-World of Aspects
public aspect SimpleTracing {
// trace all public method calls in com.trcinc.*
private pointcut trace(): call(* com.trcinc..*.*.*(..));
before(): trace() {
String name = thisJoinPoint.getSignature().getName();
TraceSupport.traceEntry(name);
}
after(): returning: trace() {
String name = thisJoinPoint.getSignature().getName();
TraceSupport.traceExit(name);
}
after(): throwing(Throwable t): trace() {
TraceSupport.logException(t);
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
29
Abstract Aspects for Reusability
public abstract aspect Tracing {
protected abstract pointcut trace();
// advice same as before
}
public aspect MyTracing extends Tracing {
// just define which calls to trace
protected pointcut trace():
call(* com.trcinc..*.*.*(..));
}
Plug’n Debug...
7/17/2015
© 2002 The Technical Resource Connection, Inc.
30
Example: Optimization
public class Fibonacci {
// naive implementation of fibonacci, resulting in a lot
// of redundant calculations of the same values.
public static int fib(int n) {
if ( n < 2) {
System.err.println(n + ".");
return 1;
} else {
public aspect Memoization { // NOT a typo...
System.err.print(n + ",");
return fib(n-1) + fib(n-2);
private HashMap cache = new HashMap();
}
}
private pointcut fibs(int in):
}
execution(int Fibonacci.fib(int)) && args(in);
public static void main(String[] args) {
int f = fib(10);
// calculate only if not already in cache!
System.err.println("Fib(10)
= " + f);
int around(int
in): fibs(in) {
}
Integer result = (Integer)cache.get(new Integer(in));
if (result == null) {
int f = proceed(in); // not found, calculate!
cache.put(new Integer(in), new Integer(f));
return f;
} else return result.intValue(); // found, done!
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
31
Example: Context Passing
caller1
Service
caller2
workers need to know the caller:
• transactions and/or security
• charge backs
• to customize result
example taken from AspectJ
tutorial
7/17/2015
worker 1
worker 2
© 2002 The Technical Resource Connection, Inc.
worker 3
32
Example: Context Passing
caller1
Service
caller2
Define these
pointcuts
worker 1
7/17/2015
worker 2
© 2002 The Technical Resource Connection, Inc.
worker 3
33
Example: Context Passing
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
7/17/2015
© 2002 The Technical Resource Connection, Inc.
34
Example: Context Passing
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
7/17/2015
© 2002 The Technical Resource Connection, Inc.
35
Example: Context Passing
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
pointcut perCallerWork(Caller c, Worker w):
cflow(invocations(c)) && workPoints(w);
7/17/2015
© 2002 The Technical Resource Connection, Inc.
36
Example: Context Passing
pointcut invocations(Caller c):
this(c) && call(void Service.doService(String));
pointcut workPoints(Worker w):
target(w) && call(void Worker.doTask(Task));
pointcut perCallerWork(Caller c, Worker w):
cflow(invocations(c)) && workPoints(w);
before (Caller c, Worker w): perCallerWork(c, w)
{
w.checkAllowed(c);
}
after (Caller c, Worker w) returning:
perCallerWork(c, w)
{
c.chargeForWork(w);
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
37
Example: Context Passing
JoinPoint
We’ve created a wormhole !
7/17/2015
© 2002 The Technical Resource Connection, Inc.
38
AspectJ Wormhole Theory
cflow
ptc1
= cflow(ptc1)&& ptc2
ptc2
7/17/2015
© 2002 The Technical Resource Connection, Inc.
39
Summary of Dynamic Features of AspectJ
Pointcuts (composable with && , || , ! ):
–
–
–
–
–
–
–
call(signature), execution(signature)
get(fields), set(fields)
handler(exception)
initialization, staticinitialization
cflow(ptc), cflowbelow(ptc)
this(typePattern or id), target(typePattern or Id)
within(TypePattern), withincode(Signature)
advice:
– before, after around
Some powerful Idioms:
– wormhole: cflow(ptc1) && ptc2
– non-reentrant: ptc && !cflowbelow(ptc)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
40
Untangle Your Code with Aspect-Oriented
Programming (AOP): Part Two
The Technical Resource Connection, Inc.
More AspectJ, Design Patterns and Transactional Objects
AspectJ Terminology
Introduction (aka “Open Classes”):
An aspect can introduce new structure and behavior on
existing classes and interfaces. These are called introductions.
Simple example:
declare parents: domain.* implements Serializable;
write this in an aspect and all classes in the domain package
automagically become serializable objects...
7/17/2015
© 2002 The Technical Resource Connection, Inc.
42
Example Introduction
aspect CloneablePoint {
declare parents: Point implements Cloneable;
public Object Point.clone() throws CloneNotSupportedException {
return super.clone();
}
}
By introducing the clone method in the Point class itself , we can
now clone Point objects. ClonablePoint is not a class. It cannot be
instantiated.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
43
More Introductions
AspectJ lets you introduce fields and concrete methods (with
bodies!) on interfaces! Example:
aspect TransactionalObjects {
interface Persistent {}
private String Persistent.uuid = UUID.getUUID();
public String Persistent.getUUID() {
return uuid;
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
44
Aspect Instances
By default aspects are singletons
Can be modified using keywords:
– perthis(pointcut)
create an instance per object that can ever be “this” at a joinpoint
– pertarget(pointcut)
create an instance per object that can ever be the target of a joinpoint
– percflow(pointcut)
create one instance for each flow of control of the join points picked out by pointcut
7/17/2015
© 2002 The Technical Resource Connection, Inc.
45
Example perthis(pointcut)
Public aspect ObserverPattern perthis(observed()) {
// objects being observed
abstract pointcut observed();
// this aspect state is the reason each observed
// object must have its own aspect instance.
Vector observers = new Vector();
public static void addObserver(Observed m, Observer v) {
ObserverPattern.aspectOf(m).observers.add(v);
}
}
Generated by ajc for
concrete perthis aspects
7/17/2015
© 2002 The Technical Resource Connection, Inc.
46
Design Patterns as Reusable Components Using Aspects
Abstract aspects can be used to encapsulate the inter-object
protocols of behavioral patterns in a single place.
The abstract pattern works with interfaces and/or abstract
pointcuts
To re-use a pattern, subclass it and introduce the interfaces on
your classes or make the pointcuts concrete.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
47
Example: JavaBean Observer
Goals:
– encapsulate relationships between observer and observed in a single
–
–
–
–
7/17/2015
place
automatically inject these relationships into existing classes
classes are unaware of the pattern
pattern is unaware of the classes
use the Javabean conventions, for example, getProp and setProp
methods and PropertyChangeEvents
© 2002 The Technical Resource Connection, Inc.
48
Example: JavaBean Observer
public abstract aspect ObserverPattern {
Pattern works with any
implementation of Observer
public interface Observer extends PropertyChangeListener {
}
Pattern works with any
implementation of Observed
public interface Observed {
public void addPropertyChangeListener(PropertyChangeListener l);
public void removePropertyChangeListener(PropertyChangeListener l);
};
Every Observed needs a
PropertyChangeSupport object.
PropertyChangeSupport Observed.pss;
public void Observed.addPropertyChangeListener(PropertyChangeListener l) {
if (pss == null) pss = new PropertyChangeSupport(this);
pss.addPropertyChangeListener(l);
}
Code to add property
public
void Observed.removePropertyChangeListener(PropertyChangeListener
l) {
change
listeners
is the same
if (pss
== null) return;
for every
Observed,
so it can
else
pss.remove
(l);
be implemented here.
Code to remove property
}
change listeners is the same
for every Observed, so it can
be implemented here.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
49
Example: JavaBean Observer
private Object getOldValue(Object o, String property) {
try {
When calling any set method on
Method m = o.getClass().getMethod("get"
+ property,
new
Class[]{}); ‘val’,
an Observed
with
argument
return m.invoke(o, new Object[]{});
get the old value, then call the method,
} catch (Exception x) {
then fire an event.
return null;
}
}
void around(Observed o, Object val): target(o) && call(* *.set*(..)) && args(val) {
Object old = null;
String name = thisJoinPoint.getSignature().getName().substring(3);
if (o.pss != null) old = getOldValue(o, name);
Helper method to access the
proceed(o, val);
old value of a property to set in
if (o.pss != null) {
the PropertyChangeEvent
String prop = name.substring(0,1).toLowerCase() + name.substring(1);
o.pss.firePropertyChange(prop, old, val);
}
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
50
Example: JavaBean Observer
aspect DomainObserving extends ObserverPattern {
declare parents: domain.* implements Observed;
declare parents: ObserverTest implements Observer;
public void ObserverTest.propertyChange(PropertyChangeEvent evt) {
System.err.println("propertyChange " +
evt.getPropertyName() +
" old Value = " +
evt.getOldValue() +
" new value = " +
evt.getNewValue() +
" from " + evt.getSource());
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
51
IDE Integration with JBuilder
(also Forte and Emacs) shows
the impact of the aspects on
the rest of your code.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
52
Example: Visitor Untangled
Basic rules of proper dependencies:
– Acyclic Dependencies Principle (ADP): Dependencies must not form
cycles.
– Dependency Inversion Principle (DIP): Depend upon abstractions, do
not depend upon concretions.
– Stable Dependencies Principle (SDP): Depend in the direction of
stability.
from R.C Martin, “Design Principles and Design Patterns, ” http://www.objectmentor.com
7/17/2015
© 2002 The Technical Resource Connection, Inc.
53
Example: Visitor Untangled
This figure graphically illustrates the previous rules.
More reusable
class
Useless
class
Unmaintainable
class
Less reusable
class
concrete
DIP
abstract
from “Aspect-Oriented Dependency Inversion ” by Martin E. Nordberg III
stable
7/17/2015
SDP
unstable
© 2002 The Technical Resource Connection, Inc.
54
Example: Visitor Untangled
This figure contains the components of the Visitor pattern
plotted on the DIP/SDP field.
Visitor violates all three of the rules!
abstract
from “Aspect-Oriented Dependency Inversion ” by Martin E. Nordberg III
Visitor
DIP
Element
ADP
DIP
SDP
concrete
Concrete
Element
Concrete
Visitor
stable
7/17/2015
SDP
unstable
© 2002 The Technical Resource Connection, Inc.
55
Example: Visitor Untangled
Using AOP eliminates the Visitor’s deadly cyclic dependency. . .
Simply augment the element classes with the new operation’s code. No
more Visitor interface needed.
abstract
from “Aspect-Oriented Dependency Inversion ” by Martin E. Nordberg III
augments
DIP
Element
concrete
Concrete
Element
Concrete
Aspect
stable
7/17/2015
augments
SDP
unstable
© 2002 The Technical Resource Connection, Inc.
56
Transactional Java Objects (TJO)
The Technical Resource Connection, Inc.
Implemented with AOP using AspectJ
Transactional Java Objects (TJO)
Allow any collection of objects to behave in a transactional
manner:
– All modifications to these objects are tracked.
– ABORT triggers a rollback of all modifications.
– “container-managed” and manual transactions
– Nested transactions (in EJB terms, REQUIRESNEW vs. REQUIRES)
– Give all objects a universally unique ID (UUID).
7/17/2015
© 2002 The Technical Resource Connection, Inc.
58
TJO: Example Domain Objects
Person
Address
String firstName
String lastName
String getFirstName()
void setFirstName(String)
String getLastName()
void setLastName(String)
Address getAddress()
void setAddress(Address)
void doSomethingIllegal()
address String
String
0..1
String
String
String
line1
line2
city
zip
state
String getLine1()
void setLine1(String)
String getLine2()
void setLine2(String)
String getCity()
void setCity(String)
String getState()
void setState(String)
Customer
*
double credit
double getCredit()
void setCredit(double)
void incCredit(double)
void addShippingAddress(Address)
void removeShippingAddress(Address)
void clearShippingAddresses()
7/17/2015
shippingAddress
© 2002 The Technical Resource Connection, Inc.
59
TJO: Example Rollback Test Case
public void testUpdate() {
String lastName = c.getLastName();
String city = c.getAddress().getCity();
1. Call
double credit = c.getCredit();
transactional
try {
updateCustomer();
fail("Expected NullPointerException.");
} catch (Exception x) {
2. Which
assertEquals(c.getLastName(), lastName);
assertEquals(credit, c.getCredit(), 0.0);
assertEquals(city, c.getAddress().getCity());
}
}
public void updateCustomer() {
c.getAddress().setCity("Tampa");
c.setLastName(”Power");
c.incCredit(30.0);
c.doSomethingIllegal(); // throws exception
} // ABORT
7/17/2015
© 2002 The Technical Resource Connection, Inc.
a
method
aborts
3. After which old
values should have
been restored
60
TJO: Using it for Your Objects
public aspect MyTransactionalObjects extends TransactionalObjects {
declare parents: domain.* implements Persistent;
// like REQUIRESNEW in EJB, these methods will ALWAYS start a NEW transaction
protected pointcut requiresnew():
call(* Main.cmNestedAbort(..)) ||
call(* Main.cmNestedCommit(..));
// these methods will start a transaction or attach to an existing one
private pointcut requires():
call(* Main.createCustomer(..)) ||
call(* Customer.incCredit(..)) ||
call(* Main.collectionsTest(..))||
call(* Main.manualNested(..))
||
call(* Main.containerNested(..))||
call(* Main.clearAddresses(..)) ||
call(* Main.manualAbort(..))
||
call(* Main.updateCustomer(..));
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
61
TJO: Keeping track of changes
public abstract aspect TransactionalObjects {
A Persistent object o
becomes dirty when it
modifies any of its
instance variables
protected pointcut dirty(Persistent o): this(o) && set(* *.*);
protected pointcut dirtyCollection(Persistent o, Object c):
this(o) && target(c) && (
call(* java.util.Collection.add(..)) ||
call(* java.util.Collection.addAll(..)) ||
call(* java.util.Collection.remove(..)) ||
call(* java.util.Collection.clear(..)) ||
call(* java.util.Collection.removeAll(..)) ||
A persistent object o
call(* java.util.Collection.retainAll(..)) ||
might become dirty when
call(* java.util.Map.put(..)) ||
it calls any of these
call(* java.util.Map.putAll(..)) ||
collection modifying
call(* java.util.Map.clear(..)) ||
methods
call(* java.util.Map.removeAll(..)) ||
call(* java.util.Map.remove(..)) ||
call(* java.util.BitSet.clear(..)) ||
call(* java.util.BitSet.and(..)) ||
call(* java.util.BitSet.or(..)) ||
call(* java.util.BitSet.xor(..)) ||
call(* java.util.BitSet.andNot(..)));
7/17/2015
© 2002 The Technical Resource Connection, Inc.
62
TJO: Keeping Track of Changes
Before a persistent object o
becomes dirty
notify the current transaction
of this change.
before(Persistent o): dirty(o) {
String name = thisJoinPoint.getSignature().getName();
Transaction.SetModified(o,name);
}
before(Persistent o, Object c): dirtyCollection(o,c) {
Transaction.SetModifiedCollection(o, c);
}
Before a persistent object o
modifies a collection
notify the current transaction
of this change
7/17/2015
© 2002 The Technical Resource Connection, Inc.
63
TJO: “Container”-Managed Transactions
A Transaction is a toplevel
call to a method that
requires a transaction
private pointcut transaction():
requires() && !cflowbelow(requires());
Object around(): transaction() {
return commit(Transaction.Begin(
thisJoinPoint.getSignature().getName()),
proceed()); // proceed delivers return value
}
Before running a transactional
method, start a new transaction
or attach to an existing one.
If and when the method returns,
commit the transaction
Before running a nested transactional
method, always start a new
Object around(): requiresnew() {
transaction.If
and when the method
return commit(Transaction.BeginNested(
returns, commit the transaction
thisJoinPoint.getSignature().getName()),
proceed()); // proceed delivers return value
}
after() throwing: transaction() || requiresnew() {
Transaction.Abort();
}
If a transactional method
throws any exception,
abort the current
transaction.
private Object commit(Transaction t, Object returnValue) {
Transaction.Commit(t);
return returnValue;
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
64
TJO: Persistent is an “Open class”
public final String Persistent.uuid = UUID.getUUID();
Transaction Persistent.transaction = null;
Each Persistent object has a UUID
ModifiedObject Persistent.modifications = null;
Each Persistent object
participates
in one and only one
Transaction at a time
public String Persistent.getUUID() {
return uuid;
}
synchronized void Persistent.mark(Transaction t, boolean newObject)
throws WriteWriteConflictException {
if ((transaction != null) && (!t.isAncestor(transaction)))
throw new WriteWriteConflictException(transaction, this);
if (newObject) {
modifications = ModifiedObject.newObject(this);
} else {
if ((modifications == null) || (t != transaction)) {
modifications = ModifiedObject.updatedObject(this);
}
}
transaction = t;
}
Each Persistent knows
its own modifications
within the current Transaction
An object is allowed to
participate in nested transactions
of the current one. In each
Transaction a separate ModifiedObject
keeps track of changes
synchronized void Persistent.unmark() {
transaction = transaction.getParent();
if (transaction != null) {
modifications = transaction.getModifications(this);
} else {
modifications = null;
}
}
7/17/2015
© 2002 The Technical Resource Connection, Inc.
When an object is no longer part
of a transaction it still might
be part of the transaction’s parent
transaction.
65
TJO: Change Tracking Revisited
protected pointcut dirty(Persistent o): this(o) && set(* *.*) &&
// exclude the introduced fields, these cause infinite
recursion!!!
!set(* Persistent.*);
protected pointcut dirtyCollection(Persistent o, Object c):
!within(persistence.*) && this(o) && target(c) && (
call(* java.util.Collection.add(..)) ||
call(* java.util.Collection.addAll(..)) ||
call(* java.util.Collection.remove(..)) ||
call(* java.util.Collection.clear(..)) ||
call(* java.util.Collection.removeAll(..)) ||
call(* java.util.Collection.retainAll(..)) ||
call(* java.util.Map.put(..)) ||
call(* java.util.Map.putAll(..)) ||
call(* java.util.Map.clear(..)) ||
call(* java.util.Map.removeAll(..)) ||
call(* java.util.Map.remove(..)) ||
call(* java.util.BitSet.clear(..)) ||
call(* java.util.BitSet.and(..)) ||
call(* java.util.BitSet.or(..)) ||
call(* java.util.BitSet.xor(..)) ||
call(* java.util.BitSet.andNot(..))
);
7/17/2015
© 2002 The Technical Resource Connection, Inc.
The TJO implementation itself
now triggers the pointcuts…
We have to exclude these
joinpoints to prevent
infinite recursion!!!
66
TJO: Transaction Framework
subtransactions
transactions
<<static>> *
<<Map with
threads as key>>
Persistent
*
Transaction
transaction
1
String uuid
1
String name
parent
public
public
public
public
static
Begin()
BeginNested
static Abort()
static Commit()
getCurrent()
abstract
abstract
abstract
abstract
begin()
preCommit()
commit(Object)
postCommit()
1
1
backups
*
<<Map with
uuid as key>>
ModifiedField
Object oldValue
Field field
modifications
ModifiedObject
Object o
rollback()
fields
*
rollback(Object o)
7/17/2015
© 2002 The Technical Resource Connection, Inc.
67
TJO: Pluggable Transactions
DefaultTransactionFactory
Transaction
static TransactionFactory factory
public Transaction create()
TransactionFactory
DefaultTransaction
JDBCTransactionFactory
SOAPTransaction
JDBCTransaction
NOTE: Factory pattern can be eliminated with another aspect. . .
7/17/2015
© 2002 The Technical Resource Connection, Inc.
68
Current State of AspectJ
AspectJ is 1.0rc2. Language is almost stable.
Not all features work unless the code is under the compiler’s
control. For example, you can’t add methods to
java.util.HashMap
weaving occurs at compile time using source. They are looking
into:
– weaving on class files
– weaving at load time in a ClassLoader
7/17/2015
© 2002 The Technical Resource Connection, Inc.
69
Other AOP Projects
Composition Filters (University of Twente in the
Netherlands)
– pioneered some of the first AOP ideas in Smalltalk in the late 80s early 90s
resulting in a language called SINA; most AOP papers reference this work.
ComposeJ and ConcernJ latest incarnations.
DJ (Northeastern University)
– Reflection-based Java framework. Lightweight version of Demeter
HyperJ (IBM Research)
– disparate but overlapping object models are hyperslices and a hypermodule
defines how to merge/integrate them. Available for download from alphaworks.
7/17/2015
© 2002 The Technical Resource Connection, Inc.
70
AOP Events
First international conference on AOP will be at the University of
Twente in the Netherlands in April 2002
7/17/2015
© 2002 The Technical Resource Connection, Inc.
71