Applying Aspect-Oriented Software Development to Middleware Frameworks
Tal Cohen
Joint work with Yossi Gil
• The problem: simplifying the design, development and modularity of enterprise applications.– Huge software programs for banks, government
agencies, etc.
• The research outcome: a set of programming language constructs.– Applicable to almost any software development
domain.
Research Overview
• The problem: simplifying the design, development and modularity of enterprise applications.– Huge software programs for banks,
government agencies, etc.
• The research outcome: a set of programming language constructs.– Applicable to almost any software
development domain.
begin::Overview
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Contributions
• Shakeins – aspect-like mechanism combining AOP with OOP.– AspectJ2EE – a proof-of-concept design for
shakeins in Enterprise Java.
• Factories – a language-level mechanism for managing object instantiation.
• JTL –a language for Query-by-Example searches in a program source.
• Object Evolution – objects can change type at runtime in type-safe systems.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Outline
• The Problem: Enterprise Application Development.– "The unbelievable complexity of simple chores"– Overview of existing solutions: middleware
frameworks, aspects…– … and why they aren't good enough
• The Solution: Shakeins– How to integrate AOP with middleware frameworks
• Additional Contributions– From better static pointcuts to dynamic shakeins
end::
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Why Programming a Banking Application is Easy
class Account {void transferTo(Account other, int amount) {
if (balance < amount)throw new OverdraftException();
this.balance -= amount;other.balance += amount;
}…
begin::ProblemO
vervie
wP
rob
lem
So
lutio
nM
ore
Re
sults
Why Programming a Banking Application is Not Easy
class Account { void transferTo(Account other, int amount) { Log.log("Attempting transfer"); User user = Security.getContext().getCurrentUser(); if (!user.canTransferFrom(this)) Log.securityError(); throw new SecurityException(); Transaction tx = Db.getConnection().beginTransaction(); this.refreshFields(); other.refreshFields(); if (balance < amount) tx.rollback(); throw new OverdraftException(); this.balance -= amount; other.balance += amount; this.updateDb(); other.updateDb(); tx.commit(); Log.log("Transfer completed"); } …
SECURITY
LOGGING
BUSINESS LOGIC
TRANSACTION MANAGEMENT PERSISTENCE
Non-functional concerns yield tangled and scattered code.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Making EnterpriseDevelopment Easier
• Past: Work hard–Bonus: You get to use COBOL
• Present: Middleware Frameworks–CORBA, DCOM, Enterprise Java
• Future: Aspect-Oriented Middleware Frameworks
• Past
• Present
• Future
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Middleware Frameworksand Services
• Enable large-scale, multi-tier application development.
• Provide services attachable to business logic.
• The (unreached) ideal:– You write the business logic,– The framework handles everything else.
• Services are configurable.– e.g., by XML files.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Programming a Banking Application in J2EE
class AccountBean { void transferTo(Account other, int amount) { Log.log("Attempting transfer"); if (getBalance() < amount) throw new OverdraftException(); setBalance(getBalance() – amount); other.setBalance(other.getBalance() + amount); Log.log("Transfer completed"); } …
LOGGING
BUSINESSLOGIC
<ejb-jar> <enterprise-beans> <entity> <ejb-name>Account</ejb-name> <home>come.acme.AccountHome</home> <remote>com.acme.Account</remote> <ejb-class>com.acme.AccountBean</ejb-class> <persistence-type>Container</persistence-type> …
Persistence, transactions, security:services, configured using XML files.
Not trivial to use. •e.g., can't simply access the field balance.•Several support class required (not shown) – home, interface, etc.•Somewhat easier with v5.
Set of services is pre-defined and not extensible.•So (e.g.) logging remains tangled and scattered.
Services are not programmable.•Need a different security model? No can do.•Can't control how persistence logs operations.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
AOP
Aspect-Oriented ProgrammingTo The Rescue!
• The new kid in town: a buzzword and a panacea solution to tangled and scattered code:– Decompose the system into distinct
aspects (code modules).– Develop each aspect independently.– The aspects are then woven into
a complete system.– Chief example: AspectJ
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Decomposition and Weaving
Programrequirements Aspectual
Decomposition(conceptual process)
Clearly distinctconcerns
AspectWeaving
(mechanical process)
Executable Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Programming a Banking Application with AOP
class Account { void transferTo(Account other, int amount) { if (balance < amount) throw new OverdraftException(); this.balance –= amount; other.balance += amount; } …
BUSINESSLOGIC
aspect Security { before execution of any public method in Account { User user = Security.getContext().getCurrentUser(); if (!user.canAccessAccount(this)) throw new SecurityException(); }}
aspect Logging { before execution of public methods in Account { Log.log("Began " + methodName); } after successful execution of same { Log.log(methodName + " ended successfully"); } after failed execution of same { Log.log(methodName + " caused exception: " + e); …
Everything else:defined as Aspects
Very extensible.•Define new aspects as you deem fitting.
Highly programmable.•Not just a pre-defined set of code transformations.
Reusable and configurable.•e.g., the same logging aspect can be used for many classes.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
The Problem with Aspects
• Aspects are very similar to inheritance in that they create variations on existing code.
• However, there is a schism between aspects and inheritance.– A "paradigm mismatch" between AOP and
OOP.
• Worse, aspects do not scale.– Can't handle large enterprise applications.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Aspects as Class Modifiers
• Unclear: How may an aspect modify the type?– Can it remove members?– Can it change method signatures?
• Unclear: How may an aspect modify the instance creation mechanisms?– Can it require additional constructor parameters?– Insert code before super()?
• Unclear: Does an aspect modify subclasses, too?– Does a subclass inherit from the modified version of
the class, or from the original one?– Does an advice applied to "before execution of method m()" apply to execution of overridden versions of m, too?
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Scalability?
• Versatility– AOP: Aspect application is destructive.– Enterprise apps: Legacy code must not be
broken.• Plus, different modifications of same base class
required by different parts of the program.
• Configurability– AOP: Precedence problems with multiple
aspects.– Enterprise apps: Order matters – and should
not be set globally.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Manageability?
• Granularity– AOP: An aspect may apply to any class!– Enterprise apps: Selective application
required.
• Seeing the Big Picture– AOP: Class is oblivious to aspects that
modify it– Enterprise apps: Need to know what aspects
apply to a given class
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Aspects Do Not Scale
• The AspectJ philosophy:– Throw in all program modules (classes, aspects).– Let the compiler do the mixing.
end::
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Shakeins
• The basic principle: Use OOP to implement AOP.
• Use the existing inheritance mechanism to implement class modifications.
• Suddenly, all the problems disappear.– No paradigm mismatch…
begin::Solution
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
What is a Shakein?
• A Shakein makes a re-implementation of a class.
• It does not change the type.– We get a new implementation of an existing
type.– The old implementation continues to exist!
• A parameterized, generic-like structure.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Shakeins as “Reimplements” Operators
Given a class C, shakein S, the application C’=S[p1,…,pn]<C> is a new class such that
1. C’ has the same type as C. – Cannot declare variables of type C’
2. May have additional fields.3. May have a modified behavior.
Simple subclassing:
1. Creates a subtype by adding more functions to the protocol.
2. Extends the structure definition by adding more fields.
3. Modifies the behavior by replacement and refinement
A class in OOP is:
1. A type declarationC p;
2. Template for object creation (constructor, field layout etc.)
p = new C();3. An implementation
p.m();
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Aren't These Just Mixins?
• A mixin takes a class parameter and generates a subclass.– M<C> extends C.– Encapsulates the "delta" between layers of
inheritance.
• However, unlike shakeins, mixins:– Create a new type.– Must be highly aware of the superclass.
• Can't include instructions to "add security tests to every public method".
– Unparameterized (except for the superclass).
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Shakein Example
shakein Logging { before execution of public methods { Log.log("Began " + methodName); }
after successful execution of same { Log.log(methodName + " ended successfully"); }
after failed execution of same { Log.log(methodName + " caused exception: " + e); …
Note: not "public methods in Account"
Implicit type parameter ("<T>")
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Using a Shakein
• Account accnt =
new Logging<Account>();
• The shakein application is explicit.
• The variable type is the (original) type.– Shakeins do not define new types, only new
implementations!
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Applying a Shakein to a Class Hierarchy
C1
C2
C4
C3
C1’
C2’ C3’
C4’
No inheritance relationship between the re-implementations
Since no new types are defined, this does not disturb polymorphism!
Type C1
Type C2 Type C3
Type C4
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Shakeins Do Scale
• Explicit application – no undesired classes are matched, ever.
• Original class still exists – existing code is not broken.– If the changes are desired in existing code,
only instance creation points have to be changed.
– See our work on factories…
• Explicit and flexible ordering – you can have Logging<Secure<Account>>, or Secure<Logging<Account>>, or both.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Parameterization• What if we want different instances of
Account to log into different log files?• With aspects – though luck.• With shakeins – just add a parameter to the
shakein:shakein Logging[String filename] { before execution of public methods { Log.log(filename, "Began " + methodName); } after successful execution of same { Log.log(filename, methodName + " ended"); }
…Account a = new Logging["a.log"]<Account>();Account b = new Logging["b.log"]<Account>();
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Repeated Applications
• We can even apply the same shakein more than once to the same class.– Possibly with different parameters.
• Example:
Log["pre"]<Secure<Log["post"]<Account>>>()
Log of operations before security tests.
Log of operations after security tests.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Pointcut Parameters
• A "pointcut" is the expression that specifies where the aspect/shakein code ("advice") should be injected.– Examples: "execution of public methods",
"read access of field f", etc.
• Shakeins support pointcut parameters.shakein Secure[pointcut p, String role] { before p { SecurityContext().requireRole(role); }}
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Pointcut Parameters + Repeated Application
Secure[Pt, "teller"]<
Secure[Pc, "client"]<Account>>
• Pt = execution of createNew || changeOwner– (teller-only operations)
• Pc = execution of transferTo || withdraw
– (client operations)
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Shakein Composition
shakein StdPersistence =
Transactional ○ Persistent;
shakein MySecure =
Secure[Pt, "teller"] ○
Secure[Pc, "client"];
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Other Middleware AOP Solutions
• JBoss AOP: Extension to the JBoss open-source J2EE server.– Works by bytecode manipulation.– Supports runtime application/removal of
aspects.– Susceptible to runtime failure if not configured
properly.
• Spring AOP: Open-source "lightweight" middleware framework.– Works using interceptors.– Pointcuts evaluated at runtime.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Feature ComparisonShakeinsJBoss AOPSpring
ParameterizationRepeated application
Explicit, local ordering
Pointcut parameters
Original classUntouchedPatchedUntouched
Class/type separation
Join points supported
Most of AspectJ's
All of AspectJ'sMethod execution only
Weaving mechanism
Ahead-of-time Subclassing
Patching classes at load-time
Runtime proxy generation
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Performance Comparison
• Given a class Point, apply aspects (shakeins) to confine the valid range of values for x and y.
– Classic example of repeated, parameterized application.
– Code in all 3 versions optimized for repeated application (no code duplication) rather than performance.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
How Do You Take Your Aspects?
Shaken, not stirred. end::
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
AspectJ2EE
• An integration of the shakein concept into existing J2EE frameworks and applications.
• Each service defined as a shakein.• Shakein application managed by XML
configuration files.– No expressions like
Secure[Pt, "teller"]<Secure[Pc, "client"]<Account>> appear in the code.
• J2EE Home objects ensure that all instances are created with shakeins applied.
• Deploy-time weaving.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
JTL: The Java Tools Language
• Joint research with Itay Maman and Evelina Zarivach.
• The AspectJ pointcut-specification sublanguage is generally viewed as insufficient.
• JTL is a Datalog-like language for code queries that can (among other things) replace AspectJ's pointcut sublanguage.
• Based on Query-by-Example.• No need for looping constructs.• Rich predefined predicate library.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
JTL Examples
• Search for float-typed static method:– Regular exp.: static.*float.*\(.*\)
• Inaccurate.
– AspectJ: static float *.*(..)• OK, for this specific use.
– XQuery: /class/method[.//returns/@type="float"
and @modifiers="static" ]• Insane.
– JTL: static float method
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
JTL Examples
• Another query: "any public field in a class that contains no setter or getter methods".– Regular exp.: impossible. – AspectJ: impossible.– XQuery: Possible, but…– JTL: setter := public void 'set[A-Z]?*'(_);
getter := public !void 'get[A-Z]?*'();
field_in_plain_class := public field, declared_in[C], C.members: { no getter; no setter; };
-- Given the standard library:
field_in_plain_class := public field, declared_in[C], C { no getter; no setter; };
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Factories
• Remove the need for the Abstract Factory and Factory Method design patterns.– Used extensively in middleware frameworks (e.g.,
home objects in J2EE, Bean Factory in Spring, etc.)
• Ensure all instances are created with shakeins applied – without touching client code.
• Constructors only deal with initialization; factories deal with object creation.– Including: which actual class to instantiate, or if we
should use an existing instance.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Factories
• With existing patterns: if class S is changed to become a singleton, all existing code that calls new S() must be changed to call S.getInstance().
• With factories, the change is local to S.– The factory S() will manage a single instance.
• With existing patterns: if B extends A, and A has controlled instantiation via a getInstance method, what will B.getInstance() return?
• With factories: such static methods are not needed.
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
Object Evolution
• Dynamic reclassification: allowing an object to change its type at runtime.
– e.g., prince → frog.– Supported by Smalltalk, several others.– Many real-world uses
• e.g., State design pattern.
• Type safety problems…Prince p = new Prince();if (…) p → Frog();p.drawSword(); // potential runtime type error
• Our solution: limit to monotonic changes only.– "Object evolution" -- moving down the inheritance tree.– Prince → king is okay!
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts
• I-Evolution: Movement down the inheritance tree.– Might fail if runtime type differs from static type.
• M-Evolution: Move by applying a mixin to the runtime type of the object.– No "type mismatch" possible.– Failure even less likely with idempotent mixins.
• S-Evolution: Move by applying a shakein to the runtime type of the object.– Type not changed at all (only the class), so…– Changes can be undone – still monotonic!– Result: shakeins as "dynamic aspects".
Object Evolution Flavors
• I-Evolution: Movement down the inheritance tree.– Might fail if runtime type differs from static type.
• M-Evolution: Move by applying a mixin to the runtime type of the object.– No "type mismatch" possible.– Failure even less likely with idempotent mixins.
• S-Evolution: Move by applying a shakein to the runtime type of the object.– Type not changed at all (only the class), so…– Changes can be undone – still monotonic!– Result: shakeins as "dynamic aspects".
Ove
rview
Pro
ble
mS
olu
tion
Mo
re R
esu
lts