import java.util.Map;
import java.util.Set;
+import org.aspectj.weaver.patterns.CflowPointcut;
import org.aspectj.weaver.patterns.DeclareParents;
/**
public class CrosscuttingMembersSet {
private World world;
//FIXME AV - ? we may need a sequencedHashMap there to ensure source based precedence for @AJ advice
- private Map members = new HashMap();
-
- private List shadowMungers = null;
- private List typeMungers = null;
- private List lateTypeMungers = null;
- private List declareSofts = null;
- private List declareParents = null;
- private List declareAnnotationOnTypes = null;
+ private Map /* ResolvedType (the aspect) > CrosscuttingMembers */members = new HashMap();
+
+ private List shadowMungers = null;
+ private List typeMungers = null;
+ private List lateTypeMungers = null;
+ private List declareSofts = null;
+ private List declareParents = null;
+ private List declareAnnotationOnTypes = null;
private List declareAnnotationOnFields = null;
private List declareAnnotationOnMethods= null; // includes ctors
- private List declareDominates = null;
+ private List declareDominates = null;
public CrosscuttingMembersSet(World world) {
this.world = world;
if (xcut == null) {
members.put(aspectType, aspectType.collectCrosscuttingMembers());
clearCaches();
+ CflowPointcut.clearCaches(aspectType);
change = true;
} else {
if (xcut.replaceWith(aspectType.collectCrosscuttingMembers())) {
clearCaches();
+
+ CflowPointcut.clearCaches(aspectType);
change = true;
} else {
change = false;
}
}
-// if (aspectType.isAbstract()) {
-// // we might have sub-aspects that need to re-collect their crosscutting members from us
-// boolean ancestorChange = addOrReplaceDescendantsOf(aspectType);
-// change = change || ancestorChange;
-// }
+ if (aspectType.isAbstract()) {
+ // we might have sub-aspects that need to re-collect their crosscutting members from us
+ boolean ancestorChange = addOrReplaceDescendantsOf(aspectType);
+ change = change || ancestorChange;
+ }
return change;
}
private boolean addOrReplaceDescendantsOf(ResolvedType aspectType) {
+ //System.err.println("Looking at descendants of "+aspectType.getName());
Set knownAspects = members.keySet();
Set toBeReplaced = new HashSet();
for(Iterator it = knownAspects.iterator(); it.hasNext(); ) {
- ResolvedType candidateAncestor = (ResolvedType)it.next();
- if ((candidateAncestor != aspectType) && (aspectType.isAssignableFrom(candidateAncestor))) {
- toBeReplaced.add(candidateAncestor);
+ ResolvedType candidateDescendant = (ResolvedType)it.next();
+ if ((candidateDescendant != aspectType) && (aspectType.isAssignableFrom(candidateDescendant))) {
+ toBeReplaced.add(candidateDescendant);
}
}
boolean change = false;
for (Iterator it = toBeReplaced.iterator(); it.hasNext(); ) {
- boolean thisChange = addOrReplaceAspect((ResolvedType)it.next());
+ ResolvedType next = (ResolvedType)it.next();
+ boolean thisChange = addOrReplaceAspect(next);
change = change || thisChange;
}
return change;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
}
protected Test findResidueInternal(Shadow shadow, ExposedState state) {
- throw new RuntimeException("unimplemented");
+ throw new RuntimeException("unimplemented - did concretization fail?");
}
public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
+ // the pointcut is marked as CONCRETE after returning from this
+ // call - so we can't skip concretization
// if (this.entry.state == Pointcut.SYMBOLIC) {
// // too early to concretize, return unchanged
// return this;
//make this remap from formal positions to arrayIndices
IntMap entryBindings = new IntMap();
- for (int i=0, len=freeVars.length; i < len; i++) {
+ if (freeVars!=null) {
+ for (int i=0, len=freeVars.length; i < len; i++) {
int freeVar = freeVars[i];
//int formalIndex = bindings.get(freeVar);
entryBindings.put(freeVar, i);
+ }
}
entryBindings.copyContext(bindings);
//System.out.println(this + " bindings: " + entryBindings);
List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
innerCflowEntries.removeAll(previousCflowEntries);
-
- Object field = getCflowfield(concreteEntry);
+ Object field = getCflowfield(concreteEntry,concreteAspect);
// Four routes of interest through this code (did I hear someone say refactor??)
// 1) no state in the cflow - we can use a counter *and* we have seen this pointcut
// 4) state in the cflow - we need to use a stack, but this is the first time
// we have seen this pointcut, so build the infrastructure.
- if (freeVars.length == 0) { // No state, so don't use a stack, use a counter.
+ if (freeVars==null || freeVars.length == 0) { // No state, so don't use a stack, use a counter.
ResolvedMember localCflowField = null;
// Check if we have already got a counter for this cflow pointcut
// Create shadow munger to push stuff onto the stack
concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
- Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars.length,innerCflowEntries,inAspect));
+ Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars==null?0:freeVars.length,innerCflowEntries,inAspect));
- putCflowfield(concreteEntry,localCflowField); // Remember it
+ putCflowfield(concreteEntry,concreteAspect,localCflowField); // Remember it
}
Pointcut ret = new ConcreteCflowPointcut(localCflowField, null,true);
concreteAspect.crosscuttingMembers.addTypeMunger(
world.makeCflowStackFieldAdder(localCflowField));
- putCflowfield(concreteEntry,localCflowField);
+ putCflowfield(concreteEntry,concreteAspect,localCflowField);
}
Pointcut ret = new ConcreteCflowPointcut(localCflowField, slots,false);
ret.copyLocationFrom(this);
cflowBelowFields.clear();
}
- private Object getCflowfield(Pointcut pcutkey) {
+ private String getKey(Pointcut p,ResolvedType a) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(a.getName());
+ sb.append("::");
+ sb.append(p.toString());
+ return sb.toString();
+ }
+
+ private Object getCflowfield(Pointcut pcutkey, ResolvedType concreteAspect) {
+ String key = getKey(pcutkey,concreteAspect);
+ Object o =null;
if (isBelow) {
- return cflowBelowFields.get(pcutkey);
+ o = cflowBelowFields.get(key);
} else {
- return cflowFields.get(pcutkey);
+ o = cflowFields.get(key);
}
+ //System.err.println("Retrieving for key "+key+" returning "+o);
+ return o;
}
- private void putCflowfield(Pointcut pcutkey,Object o) {
+ private void putCflowfield(Pointcut pcutkey,ResolvedType concreteAspect,Object o) {
+ String key = getKey(pcutkey,concreteAspect);
+ //System.err.println("Storing cflow field for key"+key);
if (isBelow) {
- cflowBelowFields.put(pcutkey,o);
+ cflowBelowFields.put(key,o);
} else {
- cflowFields.put(pcutkey,o);
+ cflowFields.put(key,o);
}
}
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this, data);
}
+
+ public static void clearCaches(ResolvedType aspectType) {
+ //System.err.println("Wiping entries starting "+aspectType.getName());
+ String key = aspectType.getName()+"::";
+ wipeKeys(key,cflowFields);
+ wipeKeys(key,cflowBelowFields);
+ }
+
+ private static void wipeKeys(String keyPrefix,Hashtable ht) {
+ Enumeration keys = ht.keys();
+ List forRemoval = new ArrayList();
+ while (keys.hasMoreElements()) {
+ String s = (String)keys.nextElement();
+ if (s.startsWith(keyPrefix)) forRemoval.add(s);
+ }
+ for (Iterator iter = forRemoval.iterator(); iter.hasNext();) {
+ String element = (String) iter.next();
+ ht.remove(element);
+ }
+ }
}