package org.aspectj.weaver.reflect;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.And;
import org.aspectj.weaver.ast.Call;
import org.aspectj.weaver.ast.FieldGetCall;
import org.aspectj.weaver.ast.HasAnnotation;
import org.aspectj.weaver.ast.ITestVisitor;
import org.aspectj.weaver.ast.Instanceof;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Not;
import org.aspectj.weaver.ast.Or;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
import org.aspectj.weaver.patterns.ExposedState;
import org.aspectj.weaver.tools.DefaultMatchingContext;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.aspectj.weaver.tools.MatchingContext;
import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.ShadowMatch;
public class StandardShadowMatchImpl implements ShadowMatch {
private FuzzyBoolean match;
private ExposedState state;
private Test residualTest;
private PointcutParameter[] params;
private ResolvedMember withinCode;
private ResolvedMember subject;
private ResolvedType withinType;
private MatchingContext matchContext = new DefaultMatchingContext();
public StandardShadowMatchImpl(FuzzyBoolean match, Test test, ExposedState state, PointcutParameter[] params) {
this.match = match;
this.residualTest = test;
this.state = state;
this.params = params;
}
public void setWithinCode(ResolvedMember aMember) {
this.withinCode = aMember;
}
public void setSubject(ResolvedMember aMember) {
this.subject = aMember;
}
public void setWithinType(ResolvedType aClass) {
this.withinType = aClass;
}
public boolean alwaysMatches() {
return match.alwaysTrue();
}
public boolean maybeMatches() {
return match.maybeTrue();
}
public boolean neverMatches() {
return match.alwaysFalse();
}
public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
if (neverMatches())
return JoinPointMatchImpl.NO_MATCH;
if (new RuntimeTestEvaluator(residualTest, thisObject, targetObject, args, this.matchContext).matches()) {
return new JoinPointMatchImpl(getPointcutParameters(thisObject, targetObject, args));
} else {
return JoinPointMatchImpl.NO_MATCH;
}
}
public void setMatchingContext(MatchingContext aMatchContext) {
this.matchContext = aMatchContext;
}
private PointcutParameter[] getPointcutParameters(Object thisObject, Object targetObject, Object[] args) {
return null;
}
private static class RuntimeTestEvaluator implements ITestVisitor {
private boolean matches = true;
private final Test test;
private final Object thisObject;
private final Object targetObject;
private final Object[] args;
private final MatchingContext matchContext;
public RuntimeTestEvaluator(Test aTest, Object thisObject, Object targetObject, Object[] args, MatchingContext context) {
this.test = aTest;
this.thisObject = thisObject;
this.targetObject = targetObject;
this.args = args;
this.matchContext = context;
}
public boolean matches() {
test.accept(this);
return matches;
}
public void visit(And e) {
boolean leftMatches = new RuntimeTestEvaluator(e.getLeft(), thisObject, targetObject, args, matchContext).matches();
if (!leftMatches) {
matches = false;
} else {
matches = new RuntimeTestEvaluator(e.getRight(), thisObject, targetObject, args, matchContext).matches();
}
}
public void visit(Instanceof i) {
ReflectionVar v = (ReflectionVar) i.getVar();
Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
World world = v.getType().getWorld();
ResolvedType desiredType = i.getType().resolve(world);
ResolvedType actualType = world.resolve(value.getClass().getName());
matches = desiredType.isAssignableFrom(actualType);
}
public void visit(MatchingContextBasedTest matchingContextTest) {
matches = matchingContextTest.matches(this.matchContext);
}
public void visit(Not not) {
matches = !new RuntimeTestEvaluator(not.getBody(), thisObject, targetObject, args, matchContext).matches();
}
public void visit(Or or) {
boolean leftMatches = new RuntimeTestEvaluator(or.getLeft(), thisObject, targetObject, args, matchContext).matches();
if (leftMatches) {
matches = true;
} else {
matches = new RuntimeTestEvaluator(or.getRight(), thisObject, targetObject, args, matchContext).matches();
}
}
public void visit(Literal literal) {
if (literal == Literal.FALSE) {
matches = false;
} else {
matches = true;
}
}
public void visit(Call call) {
throw new UnsupportedOperationException("Can't evaluate call test at runtime");
}
public void visit(FieldGetCall fieldGetCall) {
throw new UnsupportedOperationException("Can't evaluate fieldGetCall test at runtime");
}
public void visit(HasAnnotation hasAnnotation) {
ReflectionVar v = (ReflectionVar) hasAnnotation.getVar();
Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args);
World world = v.getType().getWorld();
ResolvedType actualVarType = world.resolve(value.getClass().getName());
ResolvedType requiredAnnotationType = hasAnnotation.getAnnotationType().resolve(world);
matches = actualVarType.hasAnnotation(requiredAnnotationType);
}
}
}