package com.revolsys.spring.security; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.support.AopUtils; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.core.Authentication; /** * Internal security-specific EvaluationContext implementation which lazily adds * the method parameter values as variables (with the corresponding parameter * names) if and when they are required. * * @author Luke Taylor * @since 3.0 */ public class MethodSecurityEvaluationContext extends StandardEvaluationContext { private static Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class); private boolean argumentsAdded; private final MethodInvocation mi; private ParameterNameDiscoverer parameterNameDiscoverer; /** * Intended for testing. Don't use in practice as it creates a new parameter * resolver for each instance. Use the constructor which takes the resolver, * as an argument thus allowing for caching. */ public MethodSecurityEvaluationContext(final Authentication user, final MethodInvocation mi) { this(user, mi, new LocalVariableTableParameterNameDiscoverer()); } public MethodSecurityEvaluationContext(final Authentication user, final MethodInvocation mi, final ParameterNameDiscoverer parameterNameDiscoverer) { this.mi = mi; this.parameterNameDiscoverer = parameterNameDiscoverer; } private void addArgumentsAsVariables() { final Object[] args = this.mi.getArguments(); if (args.length == 0) { return; } final Object targetObject = this.mi.getThis(); final Method method = AopUtils.getMostSpecificMethod(this.mi.getMethod(), targetObject.getClass()); final String[] paramNames = this.parameterNameDiscoverer.getParameterNames(method); if (paramNames == null) { logger.warn("Unable to resolve method parameter names for method: " + method + ". Debug symbol information is required if you are using parameter names in expressions."); return; } for (int i = 0; i < args.length; i++) { super.setVariable(paramNames[i], args[i]); } } @Override public Object lookupVariable(final String name) { final Object variable = super.lookupVariable(name); if (variable != null) { return variable; } if (!this.argumentsAdded) { addArgumentsAsVariables(); this.argumentsAdded = true; } return super.lookupVariable(name); } public void setParameterNameDiscoverer(final ParameterNameDiscoverer parameterNameDiscoverer) { this.parameterNameDiscoverer = parameterNameDiscoverer; } }