/* ******************************************************************* * Copyright (c) 2005 Contributors. * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v 2.0 * which accompanies this distribution and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt * * Contributors: * Adrian Colyer Initial implementation * ******************************************************************/ package org.aspectj.weaver.reflect; import java.lang.reflect.Member; import org.aspectj.util.FuzzyBoolean; 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.ast.Var; 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; /** * @author colyer Implementation of ShadowMatch for reflection based worlds. */ public class ShadowMatchImpl implements ShadowMatch { private FuzzyBoolean match; private ExposedState state; private Test residualTest; private PointcutParameter[] params; private Member withinCode; private Member subject; private Class withinType; private MatchingContext matchContext = new DefaultMatchingContext(); public ShadowMatchImpl(FuzzyBoolean match, Test test, ExposedState state, PointcutParameter[] params) { this.match = match; this.residualTest = test; this.state = state; this.params = params; } public void setWithinCode(Member aMember) { this.withinCode = aMember; } public void setSubject(Member aMember) { this.subject = aMember; } public void setWithinType(Class 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; } } /* * (non-Javadoc) * * @see org.aspectj.weaver.tools.ShadowMatch#setMatchingContext(org.aspectj.weaver.tools.MatchingContext) */ public void setMatchingContext(MatchingContext aMatchContext) { this.matchContext = aMatchContext; } private PointcutParameter[] getPointcutParameters(Object thisObject, Object targetObject, Object[] args) { Var[] vars = state.vars; PointcutParameterImpl[] bindings = new PointcutParameterImpl[params.length]; for (int i = 0; i < bindings.length; i++) { bindings[i] = new PointcutParameterImpl(params[i].getName(), params[i].getType()); bindings[i].setBinding(((ReflectionVar) vars[i]).getBindingAtJoinPoint(thisObject, targetObject, args, subject, withinCode, withinType)); } return bindings; } 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 instanceofTest) { ReflectionVar v = (ReflectionVar) instanceofTest.getVar(); Object value = v.getBindingAtJoinPoint(thisObject, targetObject, args); World world = v.getType().getWorld(); ResolvedType desiredType = instanceofTest.getType().resolve(world); if (value == null) { matches = false; } else { 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); } } }