460 likes | 552 Views
Aspect orientated programming. The problem. Code scattering class BankAccount { public void transfer( int amount,BankAccount toAccount ) { try { Log.transferringMoney (); if (authenticated( username,password ) { // do transfer
E N D
Aspect orientatedprogramming COMP 319
The problem • Code scattering class BankAccount { public void transfer(intamount,BankAccounttoAccount) { try { Log.transferringMoney(); if (authenticated(username,password) { // do transfer } } catch (TransactionExceptiontexc) { Log.storeExc(texc); } COMP319
Concerns and Cross cut concerns • Concern examples, banking • Transfer between accounts • Product statement • Make billing payment • Cross cut concerns • Security/authentication • Logging • Transaction handling COMP319
Cross cut concern problems • Scattering • Duplication • Code cloning • Tangling • Concerns not properly separated COMP319
Cross cutting concern examples and approaches • Persistence • Object-relational mapping • Internationalization • Resource bundling • Code mobility • Pre-processing • Error handling • Chained exceptions, error return codes COMP319
Definitions • Cross-cutting – Identify areas of code where common functionality exists • Advice – The code to be injected • Joinpoint – Where one or more aspects can be applied • Pointcut – A collection of joinpoints • Aspect – General term for where advice and point-cuts are combined COMP319
Terminology • Weaving – Integrating applications and aspects (e.g. AspectJ is an “aspect weaver”) • Compile-time – Can produce integrated source-code, but typically only produces woven byte-code. • Run-time – Aspects are applied “on the fly” (typically when classes are loaded) COMP319
AOP Platforms • AspectJ • Spring • JBoss AOP • AspectWerkz • Now working with AspectJ • Java Aspect Components (JAC) COMP319
AspectJ • Now an Eclipse project (http://eclipse.org/aspectj/) • Developed at Xerox PARC • Released 2001 • Latest version (AspectJ 5) is a collaboration of AspectJ and AspectWerkz • AJDT - AspectJ Development Tools plug-in for Eclipse COMP319
Aspect definition package com.aspect; public aspect DemoAspect { pointcut setterNotification() : call(* *.set*(..)); before() : setterNotification(){ System.out.println("setting data..."); } } Aspect Point-cut Advice COMP319
Aspect example (Hello World) public class Main { public static void main(String[] args) { // TODO Auto-generated method stub hello(); } public static void hello() { System.out.println("Hello"); } } COMP319
Aspect Example HelloWorld public aspect Hello { pointcuthelloCall() : execution( * Main.hello(..)); after() : helloCall() { System.out.println("World!!!"); } } COMP319
Point cut definitions //call is the most common joinpoint type call([access modifier] returnType package.ClassName.method(args)); //Examples call(* *.*(..)); //Note: “..” is also a wildcard call(public * *.set*(..)); call(void *.set*(..)); call(* *.set*(int)); call(String com.foo.Customer.set*(..)); call(* com.foo.Customer+.set*(..)); //”+” cross-cuts children call(public void com..*.set*(int)); call(* *.set*(int, ..)); call(* *.set*(int, .., String)); COMP319
Defining a pointcut • pointcut nameOfPointCut() : definition; • pointcut setters() :call(public * *.set*(..)); COMP319
Types of Join point • call(method expr) • when a method is called • execution(method expr) • when a method is executed • handler(exception expr) • when a catch block is executed COMP319
Join points public static void main(String argsv[]) { hello(); call } Public static void hello() { execution try { } catch (Exception e) { handler } } COMP319
Types of Join points • get(field expr) • when a field is read • set(field expr) • when a field is set • pointcut settingLength() : set( int SetterMonitorExample.length); • staticinitialization(class expr) • when a static block of a class is executed COMP319
Types of Join points • initialization(constructor expr) • when a constructor is executed • preinitialization(constructor expr) • when inherited constructors are executed • adviceexecution() • when an advice block is executed COMP319
Adding Advice pointcuteveryCall() : call(* *.*(..)); before() : everyCall(){ System.out.println(“Advicecalled before method"); } after() : somePointCut(){ System.out.println("Advice called after each method"); } COMP319
Anonymous point cuts in Advice before() : call(* *.*(..)) { System.out.println("Injecting advice..."); } // point cut doesn’t have name COMP319
Types of Advice • before() • Before call or body • after() returning • after() throwing • after() • around() COMP319
Types of Advice • after() returning [(type expr)] • called after normal execution of the joinpoint • after() throwing [(exception expr)] • called if the execution of the joinpoint throws the specified exception • after() • executes regardless (sort of like finally) COMP319
Types of Advice • type around() [throws exception] • executes in place of a joint point of execution • You can stop or replace code execution • To call the original code, use proceed() COMP319
Types of Advice • withincode(method expr) • true if joinpoint is within defined method • within(type expr) • true if joinpoint is within defined type (i.e. class definition) COMP319
Exception handling in Advice • after() throwing • Intercepts at method level, before the catch() block • handler(exception type) • Intercepts at the catch() block • declare soft :exception type • Wraps any exception as a RuntimeException (which consequently no longer needs to be declared in the throws clause of the method) COMP319
Exception handling advice before(java.io.FileNotFoundException exc) : handler(java.io.FileNotFoundException ) && args(exc) { System.out.println("Could not find file... message is "+exc.getMessage()); } COMP319
Point cut operators • if(expr) • evaluate boolean expression • withincode(method expr) • true if joinpoint is within defined method • within(type expr) • true if joinpoint is within defined type COMP319
Point cut operators • this(type expr) • true when joinpoint matches source object • target(type expr) • true when joinpoint matches target object • args(type expr) • true for any joinpoint matching argument type list COMP319
Getting at the context • Sometimes we want to get at • The instance of this, which is being used at the point of call • The target instance • Example fred.getX(); // fred is the target • The arguments (x and y) • Example fred.setPosition(x,y) COMP319
Getting the context • Declaring the context, type • before(BankAccount account) : • Declares the context type in the point cut, for example.. before(BankAccount account) : target(account) && authenticationNeeded() && (!execution(* BankAccount.authenticate(..))) { account.authenticate(); } • Question … Why do we have !execute(* BankAccount(authenticate()) COMP319
Arguments example pointcut settingLength(int length) : set( int SetterMonitorExample.length) && args(length); void around(int inputLength) : settingLength1(inputLength) { System.out.println("Trying to set length to "+inputLength); if (inputLength<5) { proceed(inputLength); } else { System.out.println("Skipping length setting length too large"); } } COMP319
Point cut logical operators • && • Logical AND • || • Logical OR • ! • Logical NOT COMP319
thisJoinPoint thisJoinPoint.toString() thisJoinPoint.getKind() // call, execution, set, get thisJoinPoint.getSignature(); System.out.println("thisJoinPoint.getSourceLocation(): " + thisJoinPoint.getSourceLocation(); // source code line number thisJoinPoint.getTarget(); // target object thisJoinPoint.getThis(); // source object COMP319
thisJointPoint example package testaspect; public class AspectReflectionExample { public void greet() { Greeter greeter=new Greeter("Seb"); greeter.greet("Hello "); } public static void main(String argvs[]) { AspectReflectionExampleinstance=new AspectReflectionExample(); instance.greet(); } } COMP319
thisJointPoint example package testaspect; public class Greeter { private String name=""; public void goodMorning() { System.out.println("Good morning "+name); } public void greet(String message) { System.out.println(message+name); } public Greeter(String name) { this.name=name; } } COMP319
thisJoinPoint example package testaspect; public aspect ReflectAspect { pointcut greetings(Greeter example) : call(* *.Greeter.greet(..)) && target(example); before(Greeter example) : greetings(example) { System.out.println("this: " + this); System.out.println("thisJoinPoint.toString(): " + thisJoinPoint.toString() ); System.out.println("thisJoinPoint.getKind(): " + thisJoinPoint.getKind() ); System.out.println("thisJoinPoint.toLongString(): " + thisJoinPoint.toLongString() ); System.out.println("thisJoinPoint.toShortString(): " + thisJoinPoint.toShortString() ); System.out.println("thisJoinPoint.getClass(): " + thisJoinPoint.getClass() ); System.out.println("thisJoinPoint.getSignature(): " + thisJoinPoint.getSignature() ); System.out.println("thisJoinPoint.getSourceLocation(): " + thisJoinPoint.getSourceLocation() ); System.out.println("thisJoinPoint.getTarget(): " + thisJoinPoint.getTarget() ); System.out.println("thisJoinPoint.getThis(): " + thisJoinPoint.getThis() ); } } COMP319
thisJoinpoint this: testaspect.ReflectAspect@3a3ee284 thisJoinPoint.toString(): call(void testaspect.Greeter.greet(String)) thisJoinPoint.getKind(): method-call thisJoinPoint.toLongString(): call(public void testaspect.Greeter.greet(java.lang.String)) thisJoinPoint.toShortString(): call(Greeter.greet(..)) thisJoinPoint.getClass(): class org.aspectj.runtime.reflect.JoinPointImpl thisJoinPoint.getSignature(): void testaspect.Greeter.greet(String) thisJoinPoint.getSourceLocation(): AspectReflectionExample.java:6 thisJoinPoint.getTarget(): testaspect.Greeter@37dd7056 thisJoinPoint.getThis(): testaspect.AspectReflectionExample@2afa3ac1 COMP319
Modifying target classes • Inter type declarations • Aspect can add methods, field and constructors to external class aspect SecurityChecks booleanBankAccount.authenticated=false; publicvoidBankAccount.authenticate() { if (authenticated) return; // TO DO more authentication code } public BankAccount.new(String password,String name, String pin) { } } COMP319
Modifying target classes • You can also use inter-type declarations to change the inheritance, to add new interface or new super class • New parent must be sub-class of existing parent public aspect ChangeStructure { declare parents: BankAccount implements Serializable; declare parents: BankAccount extends SecureObject; } COMP319
Intertype declarations, compile control • declare parent • declare warning • Compiler warnings result from joinpoints • declare error • Compiler errors result from joinpoints • declare precedence • Define aspect precedence COMP319
Encouraging logging, using warnings • Simple example • From Matt Chapman, AJDT Committer public aspect EnforceLogging{ pointcut scope(): within(*); pointcut printing(): get(* System.out) || get(* System.err) || call(* Throwable+.printStackTrace()); declare warning : scope() && printing(): "don't print, use the logger"; } COMP319
Class watcher example • Monitors all calls to setters • If data changes • Dirty flag=true • Application can use this to • Save data only if dirty flag=true, saves unrequired writes • Data can be discarded from cache if dirty flag=false • Supports lazy writing caches • Help data integraty testing COMP319
Watcher Example public aspect WatchSetters { // just to invoke test code below public static void main(String[] args) { Client.handleTimer(new Timer()); } private static final Class[] GETTER_ARG_TYPES = new Class[]{}; private static final Object[] GETTER_ARGS = new Object[]{}; private static final Object NONE = new Object(); public interface IWatched {} /** true if new value sent to any setter */ private boolean IWatched.dirty; /** false if unable to maintain dirty b/c no privileges, no getter... */ private boolean IWatched.dirtyValid = true; /** clients can use dirty flag */ public boolean IWatched.isDirty() { return dirty; } /** clients handle case when dirty flag is invalid */ public boolean IWatched.isDirtyValid() { return dirtyValid; } COMP319
Watcher example (Pointcut) • public pointcut setters(IWatched watched) : target(watched) && execution(void IWatched+.set*(*)); // advice uses args[0] COMP319
Watch timer advice void around(IWatched watched) : setters(watched) && if (watched.dirtyValid) { // get value by invoking getter method Object value = NONE; // no valueString getterName=“”;try { getterName = "g" + thisJoinPoint.getSignature().getName().substring(1); Method method = watched.getClass() .getMethod(getterName, GETTER_ARG_TYPES); value = method.invoke(watched, GETTER_ARGS); } catch (Throwable t) { } ; if (NONE == value) { watched.dirtyValid = false; proceed(watched); return; } // compare value with arg being set - pointcut has exactly 1 parm Object arg = thisJoinPoint.getArgs()[0]; if (!(null == arg ? value == null : arg.equals(value))) { proceed(watched); watched.dirty = true; } } COMP319
Watcher Example Persistence if (!(null == arg ? value == null : arg.equals(value))) { proceed(watched); watched.dirty = true; String tableName=thisJoinPoint.getTarget().getClass().getName(); tableName=tableName.replace(".", "_"); String sql="update "+tableName+" set "+getterName.substring(3)+"='"+arg.toString()+"' where id='"+watched.id+"'"; System.out.println("sql : "+sql); } COMP319