/* Copyright (c) 2008 Arno Haase, Andr� Arnold. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html Contributors: Arno Haase - initial API and implementation Andr� Arnold */ package org.eclipse.xtend.backend.aop; import java.util.Iterator; import org.eclipse.xtend.backend.aop.internal.AdviceScopeCounter; import org.eclipse.xtend.backend.common.ExecutionContext; import org.eclipse.xtend.backend.common.ExpressionBase; import org.eclipse.xtend.backend.common.FunctionDefContext; import org.eclipse.xtend.backend.common.SyntaxConstants; import org.eclipse.xtend.backend.util.Pair; /** * @author Arno Haase (http://www.haase-consulting.com) * @Andr� Arnold */ public final class AroundAdvice { private final ExpressionBase _body; private final Pointcut _pointcut; private FunctionDefContext _fdc; private final boolean _isCacheable; /** * * @param body contains the body of this advice * @param pointcut contains the pointcut that guards this advice * @param isCacheable This flag marks the advice as "cacheable". This means that the result of its execution * will be cached iff all advice wrapped by it, and the originally wrapped function, * are cacheable or cached, respectively. */ public AroundAdvice (ExpressionBase body, Pointcut pointcut, boolean isCacheable) { _body = body; _pointcut = pointcut; _isCacheable = isCacheable; } public ExpressionBase getBody() { return _body; } /** * actually evaluates the advice, regardless of caching - that is context sensitive and must * be taken care of by callers */ public Object evaluate (ExecutionContext ctx, AdviceScopeCounter scopeCounter, ThisJoinPoint thisJoinPoint, ThisJoinPointStaticPart thisJoinPointStaticPart) { scopeCounter.enterAdvice(); ctx.getLocalVarContext().getLocalVars().put (SyntaxConstants.THIS_JOINPOINT, thisJoinPoint); ctx.getLocalVarContext().getLocalVars().put (SyntaxConstants.THIS_JOINPOINT_STATICPART, thisJoinPointStaticPart); // TODO assign params from thisJoinPoint via _pointcut.paramTypes to _body localVarContext, see also AdvicedFunction Iterator<Pair<String, AdviceParamType>> paramTypeIt = _pointcut.getParamTypes().iterator(); Iterator<?> paramIt = thisJoinPoint.getParameters().iterator(); while (paramTypeIt.hasNext () && paramIt.hasNext ()) { Pair<String, AdviceParamType> paramType = paramTypeIt.next(); Object param = paramIt.next(); ctx.getLocalVarContext().getLocalVars().put (paramType.getFirst(), param); } final FunctionDefContext oldFdc = ctx.getFunctionDefContext(); ctx.setFunctionDefContext (_fdc); try { return _body.evaluate (ctx); } finally { ctx.setFunctionDefContext (oldFdc); ctx.getLocalVarContext ().getLocalVars ().remove (SyntaxConstants.THIS_JOINPOINT); ctx.getLocalVarContext ().getLocalVars ().remove (SyntaxConstants.THIS_JOINPOINT_STATICPART); for (Pair<String, AdviceParamType> advParamType : _pointcut.getParamTypes()) { ctx.getLocalVarContext().getLocalVars().remove (advParamType.getFirst()); } scopeCounter.leaveAdvice(); } } public void setFunctionDefContext (FunctionDefContext fdc) { _fdc = fdc; } public Pointcut getPointcut () { return _pointcut; } /** * This flag determines whether the advice is cacheable. It is intentionally * kept separate from the "cached" flag of the implementing function because * of the different semantics. */ public boolean isCacheable () { return _isCacheable; } }