package lawOfDemeter; import org.aspectj.lang.*; import java.util.*; /** * The BinStack aspect is part of a Law of Demeter Checker - a set of * classes and aspects that verify a given program does not violate * the Law of Demeter. This aspect addresses the concern of storing a stack of * bins that contain the targets being examined * * @author David H. Lorenz * @author Modifications made by Paul Freeman */ abstract aspect TargetBinStack extends Supplier { /** * Used in debugging print statements. * @return Returns a string describing what this bin contains. */ abstract String contains(); /** * This is the pointcut used by the before and after advice to stack the * target bins. */ abstract pointcut EventToStack(); /** * This is the pointcut used by the around advice to gather the objects. */ abstract pointcut EventToGather(); /** * The method that fires to the implementing aspect before the EventToGather * proceeds, signalling gathering within the implementing aspect to take place. */ abstract void gatherBefore(JoinPoint thisJoinPoint); /** * The method that fires to the implementing aspect before the EventToGather * proceeds, signalling gathering within the implementing aspect to take place. */ abstract void gatherAfter(JoinPoint thisJoinPoint, Object returnValue); /** * Advice that maintains a stack of targets. */ Stack targetStack = new Stack(); Object around(): // keep track of arguments EventToStack(){ // before a method executes, we store the current stack of targets targetStack.push(targets); // and initialize a new stack of targets targets = new HashMap(); Object returnVal = proceed(); // after the method executes, we restore the previous stack of targets targets = (HashMap)targetStack.pop(); return returnVal; } /** * Fires the gather method to the implementing aspect. The advice must occur * here in the implementing class so that it can be ordered correctly with the * gathering advice. If the gathering advice was implemented in the subclass, * it would fire before the super classes advice. The dominates keyword will not * override this. */ Object around(): EventToGather(){ gatherBefore(thisJoinPoint); Object returnValue = proceed(); gatherAfter(thisJoinPoint, returnValue); return returnValue; } /** * Prints the objects in the current bin. * Used for debugging. */ public void printTopBin(){ System.out.println("== TOP "+contains()+" =="); printHashMap(targets); System.out.println("======================"); } /** * Prints each bin in the stack. * Used for debugging. */ public void printAllBins(){ System.out.println("== ALL "+contains()+" =="); // targetStack contains one empty bin by default so start at size - 1 for(int i = targetStack.size() - 1; i >= 0; i--){ System.out.println("-- bin " + i + " --"); if(i == 0){printHashMap(targets);} else{printHashMap((HashMap)targetStack.elementAt(i - 1));} System.out.println("-------------------"); } System.out.println("======================"); } }