]> source.dussan.org Git - aspectj.git/commitdiff
permit extensions to pointcut designator set when using weaver tools API
authoracolyer <acolyer>
Tue, 13 Dec 2005 15:52:47 +0000 (15:52 +0000)
committeracolyer <acolyer>
Tue, 13 Dec 2005 15:52:47 +0000 (15:52 +0000)
18 files changed:
weaver/src/org/aspectj/weaver/ast/ITestVisitor.java
weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java
weaver/src/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/internal/tools/PointcutExpressionImpl.java
weaver/src/org/aspectj/weaver/patterns/PatternParser.java
weaver/src/org/aspectj/weaver/patterns/Pointcut.java
weaver/src/org/aspectj/weaver/reflect/ReflectionShadow.java
weaver/src/org/aspectj/weaver/reflect/ShadowMatchImpl.java
weaver/src/org/aspectj/weaver/tools/ContextBasedMatcher.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/tools/DefaultMatchingContext.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/tools/MatchingContext.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/tools/PointcutDesignatorHandler.java [new file with mode: 0644]
weaver/src/org/aspectj/weaver/tools/PointcutExpression.java
weaver/src/org/aspectj/weaver/tools/PointcutParser.java
weaver/src/org/aspectj/weaver/tools/ShadowMatch.java
weaver/testsrc/org/aspectj/weaver/tools/PointcutDesignatorHandlerTests.java [new file with mode: 0644]
weaver/testsrc/org/aspectj/weaver/tools/ToolsTests.java

index 67035e6dc209d8d70884868fe31715ff4d908b2e..a80a8509c2e0c179bab8840a5fc6df8082223bcd 100644 (file)
@@ -13,6 +13,8 @@
 
 package org.aspectj.weaver.ast;
 
+import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
+
 
 public interface ITestVisitor {
 
@@ -24,5 +26,6 @@ public interface ITestVisitor {
        void visit(Call call);
        void visit(FieldGetCall fieldGetCall);
        void visit(HasAnnotation hasAnnotation);
+       void visit(MatchingContextBasedTest matchingContextTest);
 
 }
index 25586fbdd8e187bf233d6985b8a5fb03a439cb48..f879633fd077e9d7521e920f1a0c213d2eeb4035 100644 (file)
@@ -42,6 +42,7 @@ import org.aspectj.weaver.ast.Or;
 import org.aspectj.weaver.ast.StringConstExpr;
 import org.aspectj.weaver.ast.Test;
 import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
 
 // we generate right to left, btw.
 public class BcelRenderer implements ITestVisitor, IExprVisitor {
@@ -202,6 +203,13 @@ public class BcelRenderer implements ITestVisitor, IExprVisitor {
         hasAnnotation.getVar().accept(this);
     }
     
+    /* (non-Javadoc)
+     * @see org.aspectj.weaver.ast.ITestVisitor#visit(org.aspectj.weaver.internal.tools.MatchingContextBasedTest)
+     */
+    public void visit(MatchingContextBasedTest matchingContextTest) {
+       throw new UnsupportedOperationException("matching context extension not supported in bytecode weaving");
+    }
+    
        private InstructionList createJumpBasedOnBooleanOnStack() {
                InstructionList il = new InstructionList();
         if (sk == fk) {
diff --git a/weaver/src/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java b/weaver/src/org/aspectj/weaver/internal/tools/MatchingContextBasedTest.java
new file mode 100644 (file)
index 0000000..b5a78e0
--- /dev/null
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import org.aspectj.weaver.ast.ITestVisitor;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.tools.MatchingContext;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+
+/**
+ * Test that uses MatchingContext to match (or not)
+ *
+ */
+public class MatchingContextBasedTest extends Test {
+
+       private final ContextBasedMatcher matcher;
+       
+       public MatchingContextBasedTest(ContextBasedMatcher pc) {
+               this.matcher = pc;
+       }
+       
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.ast.Test#accept(org.aspectj.weaver.ast.ITestVisitor)
+        */
+       public void accept(ITestVisitor v) {
+               v.visit(this);
+       }
+       
+       public boolean matches(MatchingContext context) {
+               return this.matcher.matchesDynamically(context);
+       }
+
+}
diff --git a/weaver/src/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java b/weaver/src/org/aspectj/weaver/internal/tools/PointcutDesignatorHandlerBasedPointcut.java
new file mode 100644 (file)
index 0000000..3934f56
--- /dev/null
@@ -0,0 +1,152 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.internal.tools;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+import org.aspectj.util.FuzzyBoolean;
+import org.aspectj.weaver.IntMap;
+import org.aspectj.weaver.ResolvedType;
+import org.aspectj.weaver.Shadow;
+import org.aspectj.weaver.ast.Literal;
+import org.aspectj.weaver.ast.Test;
+import org.aspectj.weaver.patterns.Bindings;
+import org.aspectj.weaver.patterns.ExposedState;
+import org.aspectj.weaver.patterns.FastMatchInfo;
+import org.aspectj.weaver.patterns.IScope;
+import org.aspectj.weaver.patterns.PatternNodeVisitor;
+import org.aspectj.weaver.patterns.Pointcut;
+import org.aspectj.weaver.reflect.ReflectionShadow;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+import org.aspectj.weaver.tools.MatchingContext;
+
+/**
+ * Implementation of Pointcut that is backed by a user-extension
+ * pointcut designator handler.
+ *
+ */
+public class PointcutDesignatorHandlerBasedPointcut extends Pointcut{
+
+       private final ContextBasedMatcher matcher;
+       private final ReflectionWorld world;
+       
+       public PointcutDesignatorHandlerBasedPointcut(
+                       ContextBasedMatcher expr, 
+                       ReflectionWorld world) {
+               this.matcher = expr;
+               this.world = world;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#getPointcutKind()
+        */
+       public byte getPointcutKind() {
+               return Pointcut.USER_EXTENSION;
+       }
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#fastMatch(org.aspectj.weaver.patterns.FastMatchInfo)
+        */
+       public FuzzyBoolean fastMatch(FastMatchInfo info) {
+               try {
+                       return FuzzyBoolean.fromBoolean(
+                               this.matcher.couldMatchJoinPointsInType(
+                                               Class.forName(info.getType().getName(),false,world.getClassLoader()))
+                               );
+               } catch (ClassNotFoundException cnfEx) {
+                       return FuzzyBoolean.MAYBE;
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#couldMatchKinds()
+        */
+       public Set couldMatchKinds() {
+               return Shadow.ALL_SHADOW_KINDS;
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#matchInternal(org.aspectj.weaver.Shadow)
+        */
+       protected FuzzyBoolean matchInternal(Shadow shadow) {
+               if (shadow instanceof ReflectionShadow) {
+                       MatchingContext context = ((ReflectionShadow)shadow).getMatchingContext();
+                       org.aspectj.weaver.tools.FuzzyBoolean match = 
+                               this.matcher.matchesStatically(context);
+                       if (match == org.aspectj.weaver.tools.FuzzyBoolean.MAYBE) {
+                               return FuzzyBoolean.MAYBE;
+                       } else if (match == org.aspectj.weaver.tools.FuzzyBoolean.YES) {
+                               return FuzzyBoolean.YES;
+                       } else if (match == org.aspectj.weaver.tools.FuzzyBoolean.NO) {
+                               return FuzzyBoolean.NO;
+                       }
+               }
+               throw new IllegalStateException("Can only match user-extension pcds against Reflection shadows (not BCEL)");
+       }
+       
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(org.aspectj.weaver.patterns.IScope, org.aspectj.weaver.patterns.Bindings)
+        */
+       protected void resolveBindings(IScope scope, Bindings bindings) {
+               // no-op
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#concretize1(org.aspectj.weaver.ResolvedType, org.aspectj.weaver.ResolvedType, org.aspectj.weaver.IntMap)
+        */
+       protected Pointcut concretize1(ResolvedType inAspect,
+                       ResolvedType declaringType, IntMap bindings) {
+               return this;
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#findResidueInternal(org.aspectj.weaver.Shadow, org.aspectj.weaver.patterns.ExposedState)
+        */
+       protected Test findResidueInternal(Shadow shadow, ExposedState state) {
+               if (!this.matcher.mayNeedDynamicTest()) {
+                       return Literal.TRUE;
+               } else {
+                       // could be more efficient here!
+                       matchInternal(shadow);
+                       return new MatchingContextBasedTest(this.matcher);
+               }
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.Pointcut#parameterizeWith(java.util.Map)
+        */
+       public Pointcut parameterizeWith(Map typeVariableMap) {
+               return this;
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.PatternNode#write(java.io.DataOutputStream)
+        */
+       public void write(DataOutputStream s) throws IOException {
+               throw new UnsupportedOperationException("can't write custom pointcut designator expressions to stream");
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.patterns.PatternNode#accept(org.aspectj.weaver.patterns.PatternNodeVisitor, java.lang.Object)
+        */
+       public Object accept(PatternNodeVisitor visitor, Object data) {
+               //visitor.visit(this);
+               // no-op?
+               return data;
+       }
+
+}
index fd0558cd86ff050439de3df845c970ba27b79812..631cadcad300b625e99bc31722b3baec1c480e85 100644 (file)
@@ -32,6 +32,8 @@ import org.aspectj.weaver.patterns.ThisOrTargetAnnotationPointcut;
 import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
 import org.aspectj.weaver.reflect.ReflectionShadow;
 import org.aspectj.weaver.reflect.ShadowMatchImpl;
+import org.aspectj.weaver.tools.DefaultMatchingContext;
+import org.aspectj.weaver.tools.MatchingContext;
 import org.aspectj.weaver.tools.PointcutExpression;
 import org.aspectj.weaver.tools.PointcutParameter;
 import org.aspectj.weaver.tools.ShadowMatch;
@@ -45,6 +47,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        private Pointcut pointcut;
        private String expression;
        private PointcutParameter[] parameters;
+       private MatchingContext matchContext = new DefaultMatchingContext();
        
        public PointcutExpressionImpl(Pointcut pointcut, String expression, PointcutParameter[] params, World inWorld) {
                this.pointcut = pointcut;
@@ -58,6 +61,13 @@ public class PointcutExpressionImpl implements PointcutExpression {
                return this.pointcut;
        }
        
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.tools.PointcutExpression#setMatchingContext(org.aspectj.weaver.tools.MatchingContext)
+        */
+       public void setMatchingContext(MatchingContext aMatchContext) {
+               this.matchContext = aMatchContext;
+       }
+       
        public boolean couldMatchJoinPointsInType(Class aClass) {
                return pointcut.fastMatch(new FastMatchInfo(world.resolve(aClass.getName()),null)).maybeTrue();
        }
@@ -81,7 +91,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        private ShadowMatch matchesExecution(Member aMember) {
-               Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember);
+               Shadow s = ReflectionShadow.makeExecutionShadow(world, aMember,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aMember);
                sm.setWithinCode(null);
@@ -90,7 +100,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesStaticInitialization(Class aClass) {
-               Shadow s = ReflectionShadow.makeStaticInitializationShadow(world, aClass);
+               Shadow s = ReflectionShadow.makeStaticInitializationShadow(world, aClass,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(null);
                sm.setWithinCode(null);
@@ -99,7 +109,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }       
        
        public ShadowMatch matchesAdviceExecution(Method aMethod) {
-               Shadow s = ReflectionShadow.makeAdviceExecutionShadow(world, aMethod);
+               Shadow s = ReflectionShadow.makeAdviceExecutionShadow(world, aMethod,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aMethod);
                sm.setWithinCode(null);
@@ -108,7 +118,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesInitialization(Constructor aConstructor) {
-               Shadow s = ReflectionShadow.makeInitializationShadow(world, aConstructor);
+               Shadow s = ReflectionShadow.makeInitializationShadow(world, aConstructor,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aConstructor);
                sm.setWithinCode(null);
@@ -117,7 +127,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesPreInitialization(Constructor aConstructor) {
-               Shadow s = ReflectionShadow.makePreInitializationShadow(world, aConstructor);
+               Shadow s = ReflectionShadow.makePreInitializationShadow(world, aConstructor,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aConstructor);
                sm.setWithinCode(null);
@@ -126,7 +136,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesMethodCall(Method aMethod, Member withinCode) {
-               Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, withinCode);
+               Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, withinCode,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aMethod);
                sm.setWithinCode(withinCode);
@@ -135,7 +145,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesMethodCall(Method aMethod, Class callerType) {
-               Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, callerType);
+               Shadow s = ReflectionShadow.makeCallShadow(world, aMethod, callerType,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aMethod);
                sm.setWithinCode(null);
@@ -144,7 +154,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesConstructorCall(Constructor aConstructor, Class callerType) {
-               Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, callerType);
+               Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor, callerType,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aConstructor);
                sm.setWithinCode(null);
@@ -153,7 +163,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesConstructorCall(Constructor aConstructor, Member withinCode) {
-               Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor,withinCode);
+               Shadow s = ReflectionShadow.makeCallShadow(world, aConstructor,withinCode,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aConstructor);
                sm.setWithinCode(withinCode);
@@ -162,7 +172,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
 
        public ShadowMatch matchesHandler(Class exceptionType, Class handlingType) {
-               Shadow s = ReflectionShadow.makeHandlerShadow(world,exceptionType,handlingType);
+               Shadow s = ReflectionShadow.makeHandlerShadow(world,exceptionType,handlingType,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(null);
                sm.setWithinCode(null);
@@ -171,7 +181,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesHandler(Class exceptionType, Member withinCode) {
-               Shadow s = ReflectionShadow.makeHandlerShadow(world,exceptionType,withinCode);
+               Shadow s = ReflectionShadow.makeHandlerShadow(world,exceptionType,withinCode,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(null);
                sm.setWithinCode(withinCode);
@@ -180,7 +190,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesFieldGet(Field aField, Class withinType) {
-               Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinType);
+               Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinType,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aField);
                sm.setWithinCode(null);
@@ -189,7 +199,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesFieldGet(Field aField, Member withinCode) {
-               Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinCode);
+               Shadow s = ReflectionShadow.makeFieldGetShadow(world, aField, withinCode,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aField);
                sm.setWithinCode(withinCode);
@@ -198,7 +208,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesFieldSet(Field aField, Class withinType) {
-               Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinType);
+               Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinType,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aField);
                sm.setWithinCode(null);
@@ -207,7 +217,7 @@ public class PointcutExpressionImpl implements PointcutExpression {
        }
        
        public ShadowMatch matchesFieldSet(Field aField, Member withinCode) {
-               Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinCode);
+               Shadow s = ReflectionShadow.makeFieldSetShadow(world, aField, withinCode,this.matchContext);
                ShadowMatchImpl sm = getShadowMatch(s);
                sm.setSubject(aField);
                sm.setWithinCode(withinCode);
@@ -222,7 +232,9 @@ public class PointcutExpressionImpl implements PointcutExpression {
                if (match.maybeTrue()) {
                        residueTest = pointcut.findResidue(forShadow, state);
                }
-               return new ShadowMatchImpl(match,residueTest,state,parameters);                         
+               ShadowMatchImpl sm = new ShadowMatchImpl(match,residueTest,state,parameters);
+               sm.setMatchingContext(this.matchContext);
+               return sm;
        }
 
        /* (non-Javadoc)
index ede05652f210761ce2f1676ac3d1e2884f51830a..bb1eca20e308fcdb8b8c262cbed38931c008f939 100644 (file)
 package org.aspectj.weaver.patterns;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.aspectj.weaver.ISourceContext;
 import org.aspectj.weaver.Member;
 import org.aspectj.weaver.Shadow;
 import org.aspectj.weaver.UnresolvedType;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.internal.tools.PointcutDesignatorHandlerBasedPointcut;
+import org.aspectj.weaver.reflect.ReflectionWorld;
+import org.aspectj.weaver.tools.ContextBasedMatcher;
+import org.aspectj.weaver.tools.PointcutDesignatorHandler;
 
 //XXX doesn't handle errors for extra tokens very well (sometimes ignores)
 public class PatternParser {
@@ -31,6 +39,10 @@ public class PatternParser {
        
        /** not thread-safe, but this class is not intended to be... */
        private boolean allowHasTypePatterns = false;
+       
+       /** extension handlers used in weaver tools API only */
+       private Set pointcutDesignatorHandlers = Collections.EMPTY_SET;
+       private ReflectionWorld world;
 
        /**
         * Constructor for PatternParser.
@@ -40,6 +52,12 @@ public class PatternParser {
                this.tokenSource = tokenSource;
                this.sourceContext = tokenSource.getSourceContext();
        }
+       
+       /** only used by weaver tools API */
+       public void setPointcutDesignatorHandlers(Set handlers, ReflectionWorld world) {
+               this.pointcutDesignatorHandlers = handlers;
+               this.world = world;
+       }
 
        public PerClause maybeParsePerClause() {
                IToken tok = tokenSource.peek();
@@ -354,10 +372,23 @@ public class PatternParser {
                                // TODO - Alex has some token stuff going on here to get a readable name in place of ""...
                                p = new IfPointcut("");
                        }
-               }
+               } 
                else {
-                       tokenSource.setIndex(start);
-                       p = parseReferencePointcut();
+                       boolean matchedByExtensionDesignator = false;
+                       // see if a registered handler wants to parse it, otherwise
+                       // treat as a reference pointcut
+                       for (Iterator iter = this.pointcutDesignatorHandlers.iterator(); iter.hasNext();) {
+                               PointcutDesignatorHandler pcd = (PointcutDesignatorHandler) iter.next();
+                               if (pcd.getDesignatorName().equals(kind)) {
+                                       p = parseDesignatorPointcut(pcd);
+                                       matchedByExtensionDesignator = true;
+                               }
+                               
+                       }
+                       if (!matchedByExtensionDesignator) {
+                               tokenSource.setIndex(start);
+                               p = parseReferencePointcut();
+                       }
                }
                return p;
        }
@@ -519,6 +550,27 @@ public class PatternParser {
                TypePatternList arguments = parseArgumentsPattern();
                return new ReferencePointcut(onType, name.maybeGetSimpleName(), arguments);
        }
+       
+       private Pointcut parseDesignatorPointcut(PointcutDesignatorHandler pcdHandler) {
+               eat("(");
+               int parenCount = 1;
+               StringBuffer pointcutBody = new StringBuffer();
+               while (parenCount > 0) {
+                       if (maybeEat("(")) {
+                               parenCount++;
+                               pointcutBody.append("(");
+                       } else if (maybeEat(")")) {
+                               parenCount--;
+                               if (parenCount > 0) {
+                                       pointcutBody.append(")");
+                               }
+                       } else {
+                               pointcutBody.append(nextToken().getString());
+                       }
+               }
+               ContextBasedMatcher pcExpr = pcdHandler.parse(pointcutBody.toString());
+               return new PointcutDesignatorHandlerBasedPointcut(pcExpr,world);
+       }
 
 
        public List parseDottedIdentifier() {
index 1cf99da28cdac55cd282bdd37d3c901677cb1ac3..4fdf124baa1e8cd4499d80d037aab5f72028ef77 100644 (file)
@@ -175,6 +175,7 @@ public abstract class Pointcut extends PatternNode {
        public static final byte NONE = 20; // DO NOT CHANGE OR REORDER THIS SEQUENCE, THIS VALUE CAN BE PUT OUT BY ASPECTJ1.2.1
 
        public static final byte ATARGS = 21;
+       public static final byte USER_EXTENSION = 22;
 
        public byte getPointcutKind() { return pointcutKind; }
 
index a8ce5659dceeb4bf52769e91f1b8ba6ce0b3340c..6f6f98926251ecc7888287cca8623654811589ec 100644 (file)
@@ -25,6 +25,7 @@ import org.aspectj.weaver.Shadow;
 import org.aspectj.weaver.UnresolvedType;
 import org.aspectj.weaver.World;
 import org.aspectj.weaver.ast.Var;
+import org.aspectj.weaver.tools.MatchingContext;
 
 /**
  * @author colyer
@@ -32,9 +33,10 @@ import org.aspectj.weaver.ast.Var;
  */
 public class ReflectionShadow extends Shadow {
 
-       private World world;
-       private ResolvedType enclosingType;
-       private ResolvedMember enclosingMember;
+       private final World world;
+       private final ResolvedType enclosingType;
+       private final ResolvedMember enclosingMember;
+       private final MatchingContext matchContext;
        private Var thisVar = null;
        private Var targetVar = null;
        private Var[] argsVars = null;
@@ -46,118 +48,119 @@ public class ReflectionShadow extends Shadow {
        private Map annotationVar = new HashMap();
        private AnnotationFinder annotationFinder;
        
-       public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod) {
+       public static Shadow makeExecutionShadow(World inWorld, java.lang.reflect.Member forMethod, MatchingContext withContext) {
                Kind kind = (forMethod instanceof Method) ? Shadow.MethodExecution : Shadow.ConstructorExecution;
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forMethod, inWorld);
                ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null);
+               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null,withContext);
        }
        
-       public static Shadow makeAdviceExecutionShadow(World inWorld, java.lang.reflect.Method forMethod) {
+       public static Shadow makeAdviceExecutionShadow(World inWorld, java.lang.reflect.Method forMethod, MatchingContext withContext) {
                Kind kind = Shadow.AdviceExecution;
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedAdviceMember(forMethod, inWorld);
                ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null);
+               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null,withContext);
        }
        
-       public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, java.lang.reflect.Member withinCode) {
-               Shadow enclosingShadow = makeExecutionShadow(inWorld,withinCode);
+       public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, java.lang.reflect.Member withinCode, MatchingContext withContext) {
+               Shadow enclosingShadow = makeExecutionShadow(inWorld,withinCode,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
 
-       public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, Class thisClass) {
-               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, thisClass);
+       public static Shadow makeCallShadow(World inWorld, java.lang.reflect.Member aMember, Class thisClass, MatchingContext withContext) {
+               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, thisClass,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(aMember, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(thisClass, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = aMember instanceof Method ? Shadow.MethodCall : Shadow.ConstructorCall;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
 
-       public static Shadow makeStaticInitializationShadow(World inWorld, Class forType) {
+       public static Shadow makeStaticInitializationShadow(World inWorld, Class forType, MatchingContext withContext) {
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(forType, inWorld);
                ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
                Kind kind = Shadow.StaticInitialization;
-               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null);
+               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null,withContext);
        }
        
-       public static Shadow makePreInitializationShadow(World inWorld, Constructor forConstructor) {
+       public static Shadow makePreInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
                Kind kind =  Shadow.PreInitialization;
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
                ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null);
+               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null,withContext);
        }
        
-       public static Shadow makeInitializationShadow(World inWorld, Constructor forConstructor) {
+       public static Shadow makeInitializationShadow(World inWorld, Constructor forConstructor, MatchingContext withContext) {
                Kind kind =  Shadow.Initialization;
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(forConstructor, inWorld);
                ResolvedType enclosingType = signature.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null);
+               return new ReflectionShadow(inWorld,kind,signature,null,enclosingType,null,withContext);
        }
        
-       public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, Class withinType) {
+       public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, Class withinType, MatchingContext withContext) {
                Kind kind = Shadow.ExceptionHandler;
-               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, withinType);
+               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, withinType,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinType, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(withinType, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);      
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);  
        }
        
-       public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, java.lang.reflect.Member withinCode) {
+       public static Shadow makeHandlerShadow(World inWorld, Class exceptionType, java.lang.reflect.Member withinCode, MatchingContext withContext) {
                Kind kind = Shadow.ExceptionHandler;
-               Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode);
+               Shadow enclosingShadow = makeExecutionShadow(inWorld, withinCode,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createHandlerMember(exceptionType, withinCode.getDeclaringClass(), inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(withinCode, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);      
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);  
        }
        
-       public static Shadow makeFieldGetShadow(World inWorld, Field forField, Class callerType) {
-               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType);
+       public static Shadow makeFieldGetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = Shadow.FieldGet;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
        
-       public static Shadow makeFieldGetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember) {
-               Shadow enclosingShadow = makeExecutionShadow(inWorld,inMember);
+       public static Shadow makeFieldGetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember, MatchingContext withContext) {
+               Shadow enclosingShadow = makeExecutionShadow(inWorld,inMember,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = Shadow.FieldGet;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
 
-       public static Shadow makeFieldSetShadow(World inWorld, Field forField, Class callerType) {
-               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType);
+       public static Shadow makeFieldSetShadow(World inWorld, Field forField, Class callerType, MatchingContext withContext) {
+               Shadow enclosingShadow = makeStaticInitializationShadow(inWorld, callerType, withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createStaticInitMember(callerType, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = Shadow.FieldSet;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
 
-       public static Shadow makeFieldSetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember) {
-               Shadow enclosingShadow = makeExecutionShadow(inWorld,inMember);
+       public static Shadow makeFieldSetShadow(World inWorld, Field forField, java.lang.reflect.Member inMember, MatchingContext withContext) {
+               Shadow enclosingShadow = makeExecutionShadow(inWorld,inMember,withContext);
                Member signature = ReflectionBasedReferenceTypeDelegateFactory.createResolvedField(forField, inWorld);
                ResolvedMember enclosingMember = ReflectionBasedReferenceTypeDelegateFactory.createResolvedMember(inMember, inWorld);
                ResolvedType enclosingType = enclosingMember.getDeclaringType().resolve(inWorld);
                Kind kind = Shadow.FieldSet;
-               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember);
+               return new ReflectionShadow(inWorld,kind,signature,enclosingShadow,enclosingType,enclosingMember,withContext);
        }
 
-       public ReflectionShadow(World world, Kind kind, Member signature, Shadow enclosingShadow, ResolvedType enclosingType, ResolvedMember enclosingMember) {
+       public ReflectionShadow(World world, Kind kind, Member signature, Shadow enclosingShadow, ResolvedType enclosingType, ResolvedMember enclosingMember, MatchingContext withContext) {
                super(kind,signature,enclosingShadow);
                this.world = world;
                this.enclosingType = enclosingType;
                this.enclosingMember = enclosingMember;
+               this.matchContext = withContext;
                if (world instanceof ReflectionWorld) {
                        this.annotationFinder = ((ReflectionWorld)world).getAnnotationFinder();
                }
@@ -336,4 +339,7 @@ public class ReflectionShadow extends Shadow {
                return null;
        }
 
+       public MatchingContext getMatchingContext() {
+               return this.matchContext;
+       }
 }
index 1cc631e77377bada4c05ff3ceed0ccec4c4c21a5..88309b8aa32c8a7191a9d968e6c12c67221c01f7 100644 (file)
@@ -27,8 +27,11 @@ 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;
 
@@ -45,6 +48,7 @@ public class ShadowMatchImpl implements ShadowMatch {
        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;
@@ -71,12 +75,19 @@ public class ShadowMatchImpl implements ShadowMatch {
 
        public JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args) {
                if (neverMatches()) return JoinPointMatchImpl.NO_MATCH;
-               if (new RuntimeTestEvaluator(residualTest,thisObject,targetObject,args).matches()) {
+               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;
@@ -91,16 +102,19 @@ public class ShadowMatchImpl implements ShadowMatch {
        private static class RuntimeTestEvaluator implements ITestVisitor {
 
                private boolean matches = true;
-               private Test test;
-               private Object thisObject;
-               private Object targetObject;
-               private Object[] args;
+               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) {
+               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() {
@@ -110,11 +124,11 @@ public class ShadowMatchImpl implements ShadowMatch {
                
                public void visit(And e) {
                        boolean leftMatches = 
-                               new RuntimeTestEvaluator(e.getLeft(),thisObject,targetObject,args).matches();
+                               new RuntimeTestEvaluator(e.getLeft(),thisObject,targetObject,args,matchContext).matches();
                        if (!leftMatches) {
                                matches = false;
                        } else {
-                               matches = new RuntimeTestEvaluator(e.getRight(),thisObject,targetObject,args).matches();
+                               matches = new RuntimeTestEvaluator(e.getRight(),thisObject,targetObject,args,matchContext).matches();
                        }                       
                }
 
@@ -126,18 +140,22 @@ public class ShadowMatchImpl implements ShadowMatch {
                        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).matches();
+                       matches = ! new RuntimeTestEvaluator(not.getBody(),thisObject,targetObject,args,matchContext).matches();
                }
 
                public void visit(Or or) {
                        boolean leftMatches = 
-                               new RuntimeTestEvaluator(or.getLeft(),thisObject,targetObject,args).matches();
+                               new RuntimeTestEvaluator(or.getLeft(),thisObject,targetObject,args,matchContext).matches();
                        if (leftMatches) {
                                matches = true;
                        } else {
-                               matches = new RuntimeTestEvaluator(or.getRight(),thisObject,targetObject,args).matches();
+                               matches = new RuntimeTestEvaluator(or.getRight(),thisObject,targetObject,args,matchContext).matches();
                        }
                }
 
diff --git a/weaver/src/org/aspectj/weaver/tools/ContextBasedMatcher.java b/weaver/src/org/aspectj/weaver/tools/ContextBasedMatcher.java
new file mode 100644 (file)
index 0000000..92a6368
--- /dev/null
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * Pointcut expression interface for pointcut
+ * expressions returned by a
+ * PointcutDesignatorHandler. Provides an additional
+ * matching method for matching based on context
+ * information over and above that normally used
+ * by AspectJ.
+ * 
+ * @see MatchingContext
+ *
+ */
+public interface ContextBasedMatcher {
+       
+       /**
+        * return true iff this matcher could ever match
+        * a join point in the given type
+        */
+       boolean couldMatchJoinPointsInType(Class aClass);
+       
+       /**
+        * return true if matchesStatically can ever return
+        * FuzzyBoolean.MAYBE (necessitating a per-join point test
+        * to determine matching at a given join point).
+        */
+       boolean mayNeedDynamicTest();
+
+       /**
+        * Return FuzzyBoolean.YES if a join point with the given
+        * matching context is always matched. 
+        * Return FuzzyBoolean.NO if a join point with the given
+        * matching context is never matched.
+        * Return FuzzyBoolean.MAYBE if a match cannot be determined
+        * statically (whilst generating a ShadowMatch), and must
+        * be determined on a per-join point basis. 
+        */
+       FuzzyBoolean matchesStatically(MatchingContext matchContext);
+
+       /**
+        * Called during processing of ShadowMatch.matchesJoinPoint
+        * when matchesStatically returned FuzzyBoolean.MAYBE. 
+        */
+       boolean matchesDynamically(MatchingContext matchContext);
+}
diff --git a/weaver/src/org/aspectj/weaver/tools/DefaultMatchingContext.java b/weaver/src/org/aspectj/weaver/tools/DefaultMatchingContext.java
new file mode 100644 (file)
index 0000000..fa47a87
--- /dev/null
@@ -0,0 +1,56 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Default implementation of MatchingContext, backed
+ * by a Map.
+ */
+public class DefaultMatchingContext implements MatchingContext {
+
+       private Map contextMap = new HashMap();
+       
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.tools.MatchingContext#hasContextParameter(java.lang.String)
+        */
+       public boolean hasContextBinding(String contextParameterName) {
+               return this.contextMap.containsKey(contextParameterName);
+       }
+
+       /* (non-Javadoc)
+        * @see org.aspectj.weaver.tools.MatchingContext#get(java.lang.String)
+        */
+       public Object getBinding(String contextParameterName) {
+               return this.contextMap.get(contextParameterName);
+       }
+       
+       /**
+        * Add a context binding with the given name and value
+        * @param name
+        * @param value
+        */
+       public void addContextBinding(String name, Object value) {
+               this.contextMap.put(name, value);
+       }
+       
+       /**
+        * Remove the context binding with the given name
+        * @param name
+        */
+       public void removeContextBinding(String name) {
+               this.contextMap.remove(name);
+       }
+
+}
diff --git a/weaver/src/org/aspectj/weaver/tools/MatchingContext.java b/weaver/src/org/aspectj/weaver/tools/MatchingContext.java
new file mode 100644 (file)
index 0000000..e668a30
--- /dev/null
@@ -0,0 +1,43 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+/**
+ * When extending AspectJ's pointcut parsing and
+ * matching with custom PointcutDesignatorHandlers,
+ * it may be necessary to match based on context information
+ * at a join point not exposed simply by java.lang.reflect
+ * member information or argument values. The matching context
+ * interface provides an extension point for the specification
+ * of additional shadow and join point context that can be
+ * taken into account during the matching process.
+ * 
+ *  @see DefaultMatchingContext
+ */
+public interface MatchingContext {
+
+       /**
+        * Returns true iff this matching context has a defined
+        * binding for the given context parameter.
+        * @param contextParameterName
+        */
+       boolean hasContextBinding(String contextParameterName);
+       
+       /**
+        * returns the binding associated with the 
+        * given context parameter name (or null if
+        * there is no such context). 
+        * @param contextParameterName
+        * @return
+        */
+       Object getBinding(String contextParameterName);
+}
diff --git a/weaver/src/org/aspectj/weaver/tools/PointcutDesignatorHandler.java b/weaver/src/org/aspectj/weaver/tools/PointcutDesignatorHandler.java
new file mode 100644 (file)
index 0000000..63f4a81
--- /dev/null
@@ -0,0 +1,49 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+
+/**
+ * The PointcutDesignator interface allows extension of the
+ * AspectJ pointcut language so that third-party tools integrating
+ * with AspectJ can add easily their own custom 
+ * domain-specific designators and have them interoperate seamlessly
+ * with the standard AspectJ designators.
+ *
+ * A pointcut designator can only be used for matching, not for
+ * binding.
+ */
+public interface PointcutDesignatorHandler {
+
+       /**
+        * The name of this pointcut designator. For example,
+        * if this designator handles a "bean(&lt;NamePattern&gt;)
+        * format designator, this method would return "bean".
+        * @return
+        */
+       String getDesignatorName() ;
+       
+       /**
+        * Parse the given expression string
+        * and return a ContextBasedMatcher that can be used
+        * for matching.
+        * @param expression  the body of the pointcut expression. 
+        * For example, given the expression "bean(*DAO)" the parse
+        * method will be called with the argument "*DAO".
+        * @return a pointcut expression that can be used for
+        * matching.
+        * @throws IllegalArgumentException if the expression
+        * is ill-formed.
+        */
+       ContextBasedMatcher parse(String expression);
+       
+}
index 64d82a96a729e8c54a55683e93633f5207a44eb1..fe5de47ee86290e0a9bebc4cf08503cfc413100c 100644 (file)
@@ -22,6 +22,13 @@ import java.lang.reflect.Method;
  */
 public interface PointcutExpression {
 
+       /**
+        * Set the matching context to be used for
+        * subsequent calls to match.
+        * @see MatchingContext
+        */
+       void setMatchingContext(MatchingContext aMatchContext);
+       
        /**
         * Determine whether or not this pointcut could ever match a join point in the given class.
         * @param aClass  the candidate class
index d52a92687870a7acd149e1df74bfdbd47800d5ac..f4c68eff3f4c350ed6ffd6142054454dc9668258 100644 (file)
@@ -55,9 +55,10 @@ import org.aspectj.weaver.reflect.ReflectionWorld;
  */
 public class PointcutParser {
     
-       private World world;
+       private ReflectionWorld world;
        private ClassLoader classLoader;
     private Set supportedPrimitives; 
+    private Set pointcutDesignators = new HashSet();
     
     /**
      * @return a Set containing every PointcutPrimitive except
@@ -246,6 +247,23 @@ public class PointcutParser {
        getWorld().getLint().setFromProperties(properties);
     }
     
+    /**
+     * Register a new pointcut designator handler with this parser.
+     * This provides an extension mechansim for the integration of
+     * domain-specific pointcut designators with the AspectJ
+     * pointcut language.
+     * @param designatorHandler
+     */
+    public void registerPointcutDesignatorHandler(PointcutDesignatorHandler designatorHandler) {
+       this.pointcutDesignators.add(designatorHandler);
+    }
+    
+    /**
+     * Create a pointcut parameter of the given name and type.
+     * @param name
+     * @param type
+     * @return
+     */
     public PointcutParameter createPointcutParameter(String name, Class type) {
        return new PointcutParameterImpl(name,type);
     }
@@ -283,7 +301,9 @@ public class PointcutParser {
     throws UnsupportedPointcutPrimitiveException, IllegalArgumentException {
         PointcutExpressionImpl pcExpr = null;
          try {
-             Pointcut pc = new PatternParser(expression).parsePointcut();
+                PatternParser parser = new PatternParser(expression);
+                parser.setPointcutDesignatorHandlers(pointcutDesignators, world);
+             Pointcut pc = parser.parsePointcut();
              validateAgainstSupportedPrimitives(pc,expression);
              IScope resolutionScope = buildResolutionScope((inScope == null ? Object.class : inScope),formalParameters);
              pc = pc.resolve(resolutionScope);
@@ -450,6 +470,9 @@ public class PointcutParser {
                    if (!supportedPrimitives.contains(PointcutPrimitive.REFERENCE))
                        throw new UnsupportedPointcutPrimitiveException(expression, PointcutPrimitive.REFERENCE);
                    break;                      
+               case Pointcut.USER_EXTENSION:
+                       // always ok...
+                       break;
                case Pointcut.NONE:  // deliberate fall-through
                default:
                    throw new IllegalArgumentException("Unknown pointcut kind: " + pc.getPointcutKind());
index 85170f4514b799838e18b22626ee92815546417f..55e2581df01ba85fccfc6a428bf8057f62881938 100644 (file)
@@ -48,4 +48,11 @@ public interface ShadowMatch {
         * @return
         */
        JoinPointMatch matchesJoinPoint(Object thisObject, Object targetObject, Object[] args);
+       
+       /**
+        * Set a matching context to be used when matching
+        * join points.
+        * @see MatchingContext
+        */
+       void setMatchingContext(MatchingContext aMatchContext);
 }
diff --git a/weaver/testsrc/org/aspectj/weaver/tools/PointcutDesignatorHandlerTests.java b/weaver/testsrc/org/aspectj/weaver/tools/PointcutDesignatorHandlerTests.java
new file mode 100644 (file)
index 0000000..e26fe73
--- /dev/null
@@ -0,0 +1,142 @@
+/* *******************************************************************
+ * Copyright (c) 2005 Contributors.
+ * 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://eclipse.org/legal/epl-v10.html 
+ *  
+ * Contributors: 
+ *   Adrian Colyer                     Initial implementation
+ * ******************************************************************/
+package org.aspectj.weaver.tools;
+
+import junit.framework.TestCase;
+
+/**
+ * @author Adrian
+ *
+ */
+public class PointcutDesignatorHandlerTests extends TestCase {
+
+       public void testParseWithoutHandler() {
+               try {
+                       PointcutParser
+                         .getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution()
+                         .parsePointcutExpression("bean(service.*");
+                       fail("should not be able to parse bean(service.*)");
+               } catch(IllegalArgumentException ex) {
+                       assertTrue("contains bean",ex.getMessage().contains("bean"));
+               }
+       }
+       
+       public void testParseWithHandler() {
+               PointcutParser parser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
+               BeanDesignatorHandler beanHandler = new BeanDesignatorHandler();
+               parser.registerPointcutDesignatorHandler(beanHandler);
+               parser.parsePointcutExpression("bean(service.*)");
+               assertEquals("service.*",beanHandler.getExpressionLastAskedToParse());
+       }
+       
+       public void testStaticMatch() throws Exception {
+               PointcutParser parser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
+               BeanDesignatorHandler beanHandler = new BeanDesignatorHandler();
+               parser.registerPointcutDesignatorHandler(beanHandler);
+               PointcutExpression pc = parser.parsePointcutExpression("bean(myBean)");
+               DefaultMatchingContext context = new DefaultMatchingContext();
+               context.addContextBinding("beanName","myBean");
+               pc.setMatchingContext(context);
+               ShadowMatch sm = pc.matchesMethodExecution(Object.class.getMethod("toString",new Class[0]));
+               assertTrue(sm.alwaysMatches());
+               context.addContextBinding("beanName", "notMyBean");
+               sm = pc.matchesMethodExecution(Object.class.getMethod("toString",new Class[0]));
+               assertTrue(sm.neverMatches());
+       }
+       
+       public void testDynamicMatch() throws Exception {
+               PointcutParser parser = PointcutParser.getPointcutParserSupportingAllPrimitivesAndUsingContextClassloaderForResolution();
+               BeanDesignatorHandler beanHandler = new BeanDesignatorHandler();
+               beanHandler.simulateDynamicTest = true;
+               parser.registerPointcutDesignatorHandler(beanHandler);
+               PointcutExpression pc = parser.parsePointcutExpression("bean(myBean)");
+               ShadowMatch sm = pc.matchesMethodExecution(Object.class.getMethod("toString",new Class[0]));
+               DefaultMatchingContext context = new DefaultMatchingContext();
+               assertTrue(sm.maybeMatches());
+               assertFalse(sm.alwaysMatches());
+               assertFalse(sm.neverMatches());
+               context.addContextBinding("beanName","myBean");
+               sm.setMatchingContext(context);
+               assertTrue(sm.matchesJoinPoint(null, null, null).matches());
+               context.addContextBinding("beanName", "notMyBean");
+               assertFalse(sm.matchesJoinPoint(null, null, null).matches());
+       }
+       
+
+
+       private class BeanDesignatorHandler implements PointcutDesignatorHandler {
+
+               private String askedToParse;
+               public boolean simulateDynamicTest = false;
+               
+               public String getDesignatorName() {
+                       return "bean";
+               }
+       
+               /* (non-Javadoc)
+                * @see org.aspectj.weaver.tools.PointcutDesignatorHandler#parse(java.lang.String)
+                */
+               public ContextBasedMatcher parse(String expression) {
+                       this.askedToParse = expression;
+                       return new BeanPointcutExpression(expression,this.simulateDynamicTest);
+               }
+               
+               public String getExpressionLastAskedToParse() {
+                       return this.askedToParse;
+               }
+       }
+       
+       private class BeanPointcutExpression implements ContextBasedMatcher {
+
+               private final String beanNamePattern;
+               private final boolean simulateDynamicTest;
+
+               public BeanPointcutExpression(String beanNamePattern, boolean simulateDynamicTest) {
+                       this.beanNamePattern = beanNamePattern;
+                       this.simulateDynamicTest = simulateDynamicTest;                 
+               }
+
+
+               /* (non-Javadoc)
+                * @see org.aspectj.weaver.tools.ContextBasedMatcher#couldMatchJoinPointsInType(java.lang.Class)
+                */
+               public boolean couldMatchJoinPointsInType(Class aClass) {
+                       return true;
+               }
+
+
+               /* (non-Javadoc)
+                * @see org.aspectj.weaver.tools.ContextBasedMatcher#mayNeedDynamicTest()
+                */
+               public boolean mayNeedDynamicTest() {
+                       return this.simulateDynamicTest;
+               }
+
+
+               public FuzzyBoolean matchesStatically(MatchingContext matchContext) {
+                       if (this.simulateDynamicTest) return FuzzyBoolean.MAYBE;
+                       if (this.beanNamePattern.equals(matchContext.getBinding("beanName"))) {
+                               return FuzzyBoolean.YES;
+                       } else {
+                               return FuzzyBoolean.NO;
+                       }
+               }
+
+
+               /* (non-Javadoc)
+                * @see org.aspectj.weaver.tools.ContextBasedMatcher#matchesDynamically(org.aspectj.weaver.tools.MatchingContext)
+                */
+               public boolean matchesDynamically(MatchingContext matchContext) {
+                       return this.beanNamePattern.equals(matchContext.getBinding("beanName"));
+               }
+       }               
+}
\ No newline at end of file
index aa91c9f65e9a4d97a46407d435f656a5c0d9ac42..f98303ad553c321b93c4740f385a9e307cb14165 100644 (file)
@@ -20,6 +20,7 @@ public class ToolsTests {
                suite.addTestSuite(PointcutParserTest.class);
                suite.addTestSuite(PointcutExpressionTest.class);
                suite.addTestSuite(TypePatternMatcherTest.class);
+               suite.addTestSuite(PointcutDesignatorHandlerTests.class);
                //$JUnit-END$
                return suite;
        }