45
Applying Aspect- Oriented Software Development to Middleware Frameworks Tal Cohen Joint work with Yossi Gil

Applying Aspect-Oriented Software Development to Middleware Frameworks

Embed Size (px)

DESCRIPTION

Applying Aspect-Oriented Software Development to Middleware Frameworks. Tal Cohen Joint work with Yossi Gil. Research Overview. The problem : simplifying the design, development and modularity of enterprise applications . Huge software programs for banks, government agencies, etc. - PowerPoint PPT Presentation

Citation preview

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

The Problem

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

The Solution

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

Additional Results

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