package org.aspectj.weaver.patterns;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.aspectj.bridge.IMessage;
import org.aspectj.util.FileUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.CompressingDataOutputStream;
import org.aspectj.weaver.CrosscuttingMembers;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.ShadowMunger;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.patterns.ConcreteCflowPointcut.Slot;
public class CflowPointcut extends Pointcut {
private final Pointcut entry;
boolean isBelow;
private int[] freeVars;
public static final ResolvedPointcutDefinition CFLOW_MARKER = new ResolvedPointcutDefinition(null, 0, null,
UnresolvedType.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) {
this.entry = entry;
this.isBelow = isBelow;
this.freeVars = freeVars;
pointcutKind = CFLOW;
}
public boolean isCflowBelow() {
return isBelow;
}
public int couldMatchKinds() {
return Shadow.ALL_SHADOW_KINDS_BITS;
}
public Pointcut getEntry() {
return entry;
}
public FuzzyBoolean fastMatch(FastMatchInfo type) {
return FuzzyBoolean.MAYBE;
}
protected FuzzyBoolean matchInternal(Shadow shadow) {
return FuzzyBoolean.MAYBE;
}
public void write(CompressingDataOutputStream s) throws IOException {
s.writeByte(Pointcut.CFLOW);
entry.write(s);
s.writeBoolean(isBelow);
FileUtil.writeIntArray(freeVars, s);
writeLocation(s);
}
public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
ret.readLocation(context, s);
return ret;
}
public Pointcut parameterizeWith(Map<String,UnresolvedType> typeVariableMap, World w) {
CflowPointcut ret = new CflowPointcut(entry.parameterizeWith(typeVariableMap, w), isBelow, freeVars);
ret.copyLocationFrom(this);
return ret;
}
public void resolveBindings(IScope scope, Bindings bindings) {
if (bindings == null) {
entry.resolveBindings(scope, null);
entry.state = RESOLVED;
freeVars = new int[0];
} else {
Bindings entryBindings = new Bindings(bindings.size());
entry.resolveBindings(scope, entryBindings);
entry.state = RESOLVED;
freeVars = entryBindings.getUsedFormals();
bindings.mergeIn(entryBindings, scope);
}
}
public boolean equals(Object other) {
if (!(other instanceof CflowPointcut)) {
return false;
}
CflowPointcut o = (CflowPointcut) other;
return o.entry.equals(entry) && o.isBelow == isBelow;
}
public int hashCode() {
int result = 17;
result = 37 * result + entry.hashCode();
result = 37 * result + (isBelow ? 0 : 1);
return result;
}
public String toString() {
return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
}
protected Test findResidueInternal(Shadow shadow, ExposedState state) {
throw new RuntimeException("unimplemented - did concretization fail?");
}
public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
if (isDeclare(bindings.getEnclosingAdvice())) {
inAspect.getWorld().showMessage(IMessage.ERROR,
WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE, isBelow ? "below" : ""),
bindings.getEnclosingAdvice().getSourceLocation(), null);
return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
}
IntMap entryBindings = new IntMap();
if (freeVars != null) {
for (int i = 0, len = freeVars.length; i < len; i++) {
int freeVar = freeVars[i];
entryBindings.put(freeVar, i);
}
}
entryBindings.copyContext(bindings);
World world = inAspect.getWorld();
Pointcut concreteEntry;
ResolvedType concreteAspect = bindings.getConcreteAspect();
CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
Collection<ShadowMunger> previousCflowEntries = xcut.getCflowEntries();
entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
try {
concreteEntry = entry.concretize(inAspect, declaringType, entryBindings);
} finally {
entryBindings.popEnclosingDefinitition();
}
List<ShadowMunger> innerCflowEntries = new ArrayList<ShadowMunger>(xcut.getCflowEntries());
innerCflowEntries.removeAll(previousCflowEntries);
if (freeVars == null || freeVars.length == 0) {
ResolvedMember localCflowField = null;
Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "counter");
if (field != null) {
localCflowField = (ResolvedMember) field;
} else {
localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC,
NameMangler.cflowCounter(xcut), UnresolvedType.forName(NameMangler.CFLOW_COUNTER_TYPE)
.getSignature());
concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().makeCflowCounterFieldAdder(
localCflowField));
concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
localCflowField, freeVars == null ? 0 : freeVars.length, innerCflowEntries, inAspect));
putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "counter");
}
Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, null, true);
ret.copyLocationFrom(this);
return ret;
} else {
List<Slot> slots = new ArrayList<Slot>();
for (int i = 0, len = freeVars.length; i < len; i++) {
int freeVar = freeVars[i];
if (!bindings.hasKey(freeVar)) {
continue;
}
int formalIndex = bindings.get(freeVar);
ResolvedPointcutDefinition enclosingDef = bindings.peekEnclosingDefinition();
ResolvedType formalType = null;
if (enclosingDef != null && enclosingDef.getParameterTypes().length > 0) {
formalType = enclosingDef.getParameterTypes()[freeVar].resolve(world);
} else {
formalType = bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
}
ConcreteCflowPointcut.Slot slot = new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
slots.add(slot);
}
ResolvedMember localCflowField = null;
Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "stack");
if (field != null) {
localCflowField = (ResolvedMember) field;
} else {
localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC,
NameMangler.cflowStack(xcut), UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE)
.getSignature());
concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
localCflowField, freeVars.length, innerCflowEntries, inAspect));
concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport()
.makeCflowStackFieldAdder(localCflowField));
putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "stack");
}
Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, slots, false);
ret.copyLocationFrom(this);
return ret;
}
}
private String getKey(Pointcut p, ResolvedType a, String stackOrCounter) {
StringBuffer sb = new StringBuffer();
sb.append(a.getName());
sb.append("::");
sb.append(p.toString());
sb.append("::");
sb.append(stackOrCounter);
return sb.toString();
}
private Object getCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, String stackOrCounter) {
String key = getKey(pcutkey, concreteAspect, stackOrCounter);
Object o = null;
if (isBelow) {
o = xcut.getCflowBelowFields().get(key);
} else {
o = xcut.getCflowFields().get(key);
}
return o;
}
private void putCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, Object o,
String stackOrCounter) {
String key = getKey(pcutkey, concreteAspect, stackOrCounter);
if (isBelow) {
xcut.getCflowBelowFields().put(key, o);
} else {
xcut.getCflowFields().put(key, o);
}
}
public Object accept(PatternNodeVisitor visitor, Object data) {
return visitor.visit(this, data);
}
}