KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > expression > ExpressionVisitor


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.expression;
5
6
7 import java.lang.reflect.Modifier JavaDoc;
8 import java.util.ArrayList JavaDoc;
9 import java.util.List JavaDoc;
10
11 import com.tc.aspectwerkz.reflect.ClassInfo;
12 import com.tc.aspectwerkz.reflect.ClassInfoHelper;
13 import com.tc.aspectwerkz.reflect.ConstructorInfo;
14 import com.tc.aspectwerkz.reflect.FieldInfo;
15 import com.tc.aspectwerkz.reflect.MemberInfo;
16 import com.tc.aspectwerkz.reflect.MethodInfo;
17 import com.tc.aspectwerkz.reflect.ReflectionInfo;
18 import com.tc.aspectwerkz.reflect.StaticInitializationInfo;
19 import com.tc.backport175.bytecode.AnnotationElement;
20 import com.tc.aspectwerkz.expression.ExpressionInfo;
21
22 import com.tc.aspectwerkz.expression.ast.*;
23 import com.tc.aspectwerkz.expression.regexp.Pattern;
24 import com.tc.aspectwerkz.expression.regexp.TypePattern;
25 import com.tc.aspectwerkz.util.Util;
26
27 /**
28  * The expression visitor.
29  * If a runtime residual is required (target => instance of check sometimes), Undeterministic matching is used.
30  *
31  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
32  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur </a>
33  * @author Michael Nascimento
34  * @author <a HREF="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
35  */

36 public class ExpressionVisitor implements ExpressionParserVisitor {
37
38   protected Node m_root;
39   protected String JavaDoc m_expression;
40   protected String JavaDoc m_namespace;
41
42   /**
43    * The expressionInfo this visitor is built on
44    */

45   protected ExpressionInfo m_expressionInfo;
46
47   /**
48    * Creates a new expression.
49    *
50    * @param expressionInfo the expressionInfo this visitor is built on for expression with signature
51    * @param expression the expression as a string
52    * @param namespace the namespace
53    * @param root the AST root
54    */

55   public ExpressionVisitor(final ExpressionInfo expressionInfo,
56                            final String JavaDoc expression,
57                            final String JavaDoc namespace,
58                            final Node root) {
59     m_expressionInfo = expressionInfo;
60     m_expression = expression;
61     m_namespace = namespace;
62     m_root = root;
63   }
64
65   /**
66    * Matches the expression context.
67    * If undetermined, assume true.
68    * Do not use for poincut reference - see matchUndeterministic
69    *
70    * @param context
71    * @return
72    */

73   public boolean match(final com.tc.aspectwerkz.expression.ExpressionContext context) {
74     Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
75     // undeterministic is assumed to be "true" at this stage
76
// since it won't be composed anymore with a NOT (unless
77
// thru pointcut reference ie a new visitor)
78
return (match != null) ? match.booleanValue() : true;
79   }
80
81   protected Boolean JavaDoc matchUndeterministic(final ExpressionContext context) {
82     Boolean JavaDoc match = ((Boolean JavaDoc) visit(m_root, context));
83     return match;
84   }
85
86   // ============ Boot strap =============
87
public Object JavaDoc visit(Node node, Object JavaDoc data) {
88     return node.jjtGetChild(0).jjtAccept(this, data);
89   }
90
91   public Object JavaDoc visit(SimpleNode node, Object JavaDoc data) {
92     return node.jjtGetChild(0).jjtAccept(this, data);
93   }
94
95   public Object JavaDoc visit(ASTRoot node, Object JavaDoc data) {
96     return node.jjtGetChild(0).jjtAccept(this, data);
97   }
98
99   public Object JavaDoc visit(ASTExpression node, Object JavaDoc data) {
100     return node.jjtGetChild(0).jjtAccept(this, data);
101   }
102
103   // ============ Logical operators =============
104
public Object JavaDoc visit(ASTOr node, Object JavaDoc data) {
105     // the AND and OR can have more than 2 nodes [see jjt grammar]
106
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
107     Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
108     Boolean JavaDoc intermediate = Undeterministic.or(matchL, matchR);
109     for (int i = 2; i < node.jjtGetNumChildren(); i++) {
110       Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
111       intermediate = Undeterministic.or(intermediate, matchNext);
112     }
113     return intermediate;
114   }
115
116   public Object JavaDoc visit(ASTAnd node, Object JavaDoc data) {
117     // the AND and OR can have more than 2 nodes [see jjt grammar]
118
Boolean JavaDoc matchL = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
119     Boolean JavaDoc matchR = (Boolean JavaDoc) node.jjtGetChild(1).jjtAccept(this, data);
120     Boolean JavaDoc intermediate = Undeterministic.and(matchL, matchR);
121     for (int i = 2; i < node.jjtGetNumChildren(); i++) {
122       Boolean JavaDoc matchNext = (Boolean JavaDoc) node.jjtGetChild(i).jjtAccept(this, data);
123       intermediate = Undeterministic.and(intermediate, matchNext);
124     }
125     return intermediate;
126   }
127
128   public Object JavaDoc visit(ASTNot node, Object JavaDoc data) {
129     Boolean JavaDoc match = (Boolean JavaDoc) node.jjtGetChild(0).jjtAccept(this, data);
130     return Undeterministic.not(match);
131   }
132
133   // ============ Pointcut types =============
134
public Object JavaDoc visit(ASTPointcutReference node, Object JavaDoc data) {
135     ExpressionContext context = (ExpressionContext) data;
136     ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
137     ExpressionVisitor expression = namespace.getExpression(node.getName());
138     return expression.matchUndeterministic(context);
139   }
140
141   public Object JavaDoc visit(ASTExecution node, Object JavaDoc data) {
142     ExpressionContext context = (ExpressionContext) data;
143     if (context.hasExecutionPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
144       return visitAnnotatedNode(node, context.getReflectionInfo());
145     } else {
146       return Boolean.FALSE;
147     }
148   }
149
150   public Object JavaDoc visit(ASTCall node, Object JavaDoc data) {
151     ExpressionContext context = (ExpressionContext) data;
152     if (context.hasCallPointcut() && (context.hasMethodInfo() || context.hasConstructorInfo())) {
153       return visitAnnotatedNode(node, context.getReflectionInfo());
154     } else {
155       return Boolean.FALSE;
156     }
157   }
158
159   public Object JavaDoc visit(ASTSet node, Object JavaDoc data) {
160     ExpressionContext context = (ExpressionContext) data;
161     if (context.hasSetPointcut() && context.hasFieldInfo()) {
162       return visitAnnotatedNode(node, context.getReflectionInfo());
163     } else {
164       return Boolean.FALSE;
165     }
166   }
167
168   public Object JavaDoc visit(ASTGet node, Object JavaDoc data) {
169     ExpressionContext context = (ExpressionContext) data;
170     if (context.hasGetPointcut() && context.hasFieldInfo()) {
171       return visitAnnotatedNode(node, context.getReflectionInfo());
172     } else {
173       return Boolean.FALSE;
174     }
175   }
176
177   public Object JavaDoc visit(ASTHandler node, Object JavaDoc data) {
178     ExpressionContext context = (ExpressionContext) data;
179     if (context.hasHandlerPointcut() && context.hasClassInfo()) {
180       return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
181     } else {
182       return Boolean.FALSE;
183     }
184   }
185
186   public Object JavaDoc visit(ASTStaticInitialization node, Object JavaDoc data) {
187     ExpressionContext context = (ExpressionContext) data;
188
189     if (context.hasStaticInitializationPointcut() && context.hasReflectionInfo()) {
190       ReflectionInfo reflectInfo = context.getReflectionInfo();
191
192       if (reflectInfo instanceof StaticInitializationInfo) {
193         ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
194
195         // In an annotated subtree, only the last child node may represent the pattern
196
Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
197         if (!(patternNode instanceof ASTAttribute)) {
198           Boolean JavaDoc matchPattern = (Boolean JavaDoc) patternNode.jjtAccept(this, reflectInfo);
199           if (Boolean.FALSE.equals(matchPattern)) {
200             return Boolean.FALSE;
201           }
202         }
203
204         // match on annotation if no pattern node or matched already
205
boolean matchedAnnotations = visitAttributes(node, declaringClassInfo);
206         if (!matchedAnnotations) {
207           return Boolean.FALSE;
208         } else {
209           return Boolean.TRUE;
210         }
211       } else {
212         return Boolean.FALSE;
213       }
214     } else {
215       return Boolean.FALSE;
216     }
217   }
218
219   public Object JavaDoc visit(ASTIf node, Object JavaDoc data) {
220     // TODO implent some day
221
return Boolean.TRUE;
222   }
223
224   public Object JavaDoc visit(ASTWithin node, Object JavaDoc data) {
225     ExpressionContext context = (ExpressionContext) data;
226     if (context.hasWithinReflectionInfo()) {
227       ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
228       ReflectionInfo withinInfo = null;
229
230       if (reflectInfo instanceof MemberInfo) {
231         withinInfo = ((MemberInfo) reflectInfo).getDeclaringType();
232       } else if (reflectInfo instanceof ClassInfo) {
233         withinInfo = reflectInfo;
234       } else {
235         return Boolean.FALSE;
236       }
237       return visitAnnotatedNode(
238               node,
239               withinInfo);
240     } else {
241       return null;
242     }
243   }
244
245   public Object JavaDoc visit(ASTWithinCode node, Object JavaDoc data) {
246     ExpressionContext context = (ExpressionContext) data;
247
248     if (!context.hasWithinReflectionInfo()) {
249       return null;
250     }
251
252     ReflectionInfo reflectInfo = context.getWithinReflectionInfo();
253
254     if (node.isStaticInitializer()) {
255       if (reflectInfo instanceof StaticInitializationInfo) {
256         // Ignore the ASTStaticInitialization node in this context
257
SimpleNode staticClinitNode = (SimpleNode) node.jjtGetChild(0);
258         ClassInfo declaringClassInfo = ((StaticInitializationInfo) reflectInfo).getDeclaringType();
259
260         boolean matchedAnnotations = visitAttributes(staticClinitNode, declaringClassInfo);
261         if (!matchedAnnotations) {
262           return Boolean.FALSE;
263         }
264
265         // In an annotated subtree, the last child node represents the pattern
266
Node lastNode = staticClinitNode.jjtGetChild(staticClinitNode.jjtGetNumChildren() - 1);
267         if (lastNode instanceof ASTAttribute) {
268           return Boolean.TRUE;
269         } else {
270           return lastNode.jjtAccept(this, reflectInfo);
271         }
272       } else {
273         return Boolean.FALSE;
274       }
275     } else {
276       return visitAnnotatedNode(
277               node,
278               reflectInfo
279       );
280     }
281   }
282
283
284   public Object JavaDoc visit(ASTHasMethod node, Object JavaDoc data) {
285     ExpressionContext context = (ExpressionContext) data;
286
287     // we are matching on the CALLER info
288
// for execution() pointcut, this is equals to CALLEE info
289
ReflectionInfo info = context.getWithinReflectionInfo();
290     ClassInfo classInfo = info instanceof MemberInfo
291             ? ((MemberInfo) info).getDeclaringType()
292             : (ClassInfo) info;
293
294     Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
295     boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
296
297     MethodInfo[] methodInfos = classInfo.getMethods();
298     for (int i = 0; i < methodInfos.length; i++) {
299       if (hasPatternNode) {
300         if (Boolean.FALSE.equals(patternNode.jjtAccept(this, methodInfos[i]))) {
301           continue;
302         }
303       }
304
305       boolean matchAnnotations = visitAttributes(node, methodInfos[i]);
306       if (matchAnnotations) {
307         return Boolean.TRUE;
308       }
309     }
310
311     ConstructorInfo[] constructorInfos = classInfo.getConstructors();
312     for (int i = 0; i < constructorInfos.length; i++) {
313       if (hasPatternNode) {
314         if (Boolean.FALSE.equals(patternNode.jjtAccept(this, constructorInfos[i]))) {
315           continue;
316         }
317       }
318
319       boolean matchAnnotations = visitAttributes(node, constructorInfos[i]);
320       if (matchAnnotations) {
321         return Boolean.TRUE;
322       }
323     }
324
325     return Boolean.FALSE;
326   }
327
328   public Object JavaDoc visit(ASTHasField node, Object JavaDoc data) {
329     ExpressionContext context = (ExpressionContext) data;
330
331     // we are matching on the CALLER info
332
// for execution() pointcut, this is equals to CALLEE info
333
ReflectionInfo info = context.getWithinReflectionInfo();
334     ClassInfo classInfo = (info instanceof MemberInfo) ?
335             ((MemberInfo) info).getDeclaringType() : (ClassInfo) info;
336
337     Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
338     boolean hasPatternNode = !(patternNode instanceof ASTAttribute);
339
340     FieldInfo[] fieldInfos = classInfo.getFields();
341     for (int i = 0; i < fieldInfos.length; i++) {
342       if (hasPatternNode) {
343         if (Boolean.FALSE.equals(patternNode.jjtAccept(this, fieldInfos[i]))) {
344           continue;
345         }
346       }
347
348       boolean matchAnnotations = visitAttributes(node, fieldInfos[i]);
349       if (matchAnnotations) {
350         return Boolean.TRUE;
351       }
352     }
353
354     return Boolean.FALSE;
355   }
356
357   public Object JavaDoc visit(ASTTarget node, Object JavaDoc data) {
358     ExpressionContext context = (ExpressionContext) data;
359     ReflectionInfo info = context.getReflectionInfo();
360
361 // //TODO - seems to be the case for AJ - not intuitive
362
// if (info instanceof ConstructorInfo) {
363
// // target(..) does not match for constructors
364
// return Boolean.FALSE;
365
// }
366
ClassInfo declaringType = null;
367     if (info instanceof MemberInfo) {
368       // if method/field is static, target(..) is evaluated to false
369
if (Modifier.isStatic(((MemberInfo) info).getModifiers())) {
370         return Boolean.FALSE;
371       }
372
373       declaringType = ((MemberInfo) info).getDeclaringType();
374     } else if (info instanceof ClassInfo) {
375       declaringType = (ClassInfo) info;
376     } else {
377       return Boolean.FALSE;
378     }
379
380     String JavaDoc boundedTypeName = node.getBoundedType(m_expressionInfo);
381     // check if the context we match is an interface call, while the bounded type of target(..) is not an
382
// interface. In such a case we will need a runtime check
383
if (declaringType.isInterface()) {
384       // if we are a instanceof (subinterface) of the bounded type, then we don't need a runtime check
385
if (ClassInfoHelper.instanceOf(declaringType, boundedTypeName)) {
386         return Boolean.TRUE;
387       } else {
388         //System.out.println("*** RT check for " + boundedTypeName + " when I am " + declaringType.getName());
389
// a runtime check with instance of will be required
390
return null;
391       }
392     } else {
393       return Util.booleanValueOf(ClassInfoHelper.instanceOf(declaringType, boundedTypeName));
394     }
395   }
396
397   public Object JavaDoc visit(ASTThis node, Object JavaDoc data) {
398     ExpressionContext context = (ExpressionContext) data;
399     // for execution pointcut, this(..) is used to match the callee info
400
// and we are assuming here that withinInfo is properly set to reflectionInfo
401
if (context.hasWithinReflectionInfo()) {
402       ReflectionInfo withinInfo = context.getWithinReflectionInfo();
403       if (withinInfo instanceof MemberInfo) {
404         // if method is static (callee for execution or caller for call/getDefault/set), this(..) is evaluated to false
405
if (Modifier.isStatic(((MemberInfo) withinInfo).getModifiers())) {
406           return Boolean.FALSE;
407         }
408         return Util.booleanValueOf(
409                 ClassInfoHelper.instanceOf(
410                         ((MemberInfo) withinInfo).getDeclaringType(),
411                         node.getBoundedType(m_expressionInfo)
412                 )
413         );
414       } else if (withinInfo instanceof ClassInfo) {
415         return Util.booleanValueOf(
416                 ClassInfoHelper.instanceOf((ClassInfo) withinInfo, node.getBoundedType(m_expressionInfo))
417         );
418       }
419     }
420     return Boolean.FALSE;
421   }
422
423   public Object JavaDoc visit(ASTCflow node, Object JavaDoc data) {
424     return null;
425   }
426
427   public Object JavaDoc visit(ASTCflowBelow node, Object JavaDoc data) {
428     return null;
429   }
430
431   // ============ Patterns =============
432
public Object JavaDoc visit(ASTClassPattern node, Object JavaDoc data) {
433     if (data instanceof ClassInfo) {
434       ClassInfo classInfo = (ClassInfo) data;
435       TypePattern typePattern = node.getTypePattern();
436
437       if (typePattern.matchType(classInfo)
438               && visitModifiers(node, classInfo)) {
439         return Boolean.TRUE;
440       } else {
441         return Boolean.FALSE;
442       }
443     } else if (data instanceof StaticInitializationInfo) {
444       ClassInfo classInfo = ((StaticInitializationInfo) data).getDeclaringType();
445
446       if (node.getTypePattern().matchType(classInfo)) {
447         return Boolean.TRUE;
448       } else {
449         return Boolean.FALSE;
450       }
451
452 // return new Boolean(node.getTypePattern().matchType(classInfo));
453
}
454
455     return Boolean.FALSE;
456   }
457
458   public Object JavaDoc visit(ASTMethodPattern node, Object JavaDoc data) {
459     if (data instanceof MethodInfo) {
460       MethodInfo methodInfo = (MethodInfo) data;
461       if (node.getMethodNamePattern().matches(methodInfo.getName())
462               && node.getDeclaringTypePattern().matchType(methodInfo.getDeclaringType())
463               && node.getReturnTypePattern().matchType(methodInfo.getReturnType())
464               && visitModifiers(node, methodInfo)
465               && visitParameters(node, methodInfo.getParameterTypes())) {
466         return Boolean.TRUE;
467       }
468     }
469
470     return Boolean.FALSE;
471   }
472
473   public Object JavaDoc visit(ASTConstructorPattern node, Object JavaDoc data) {
474     if (data instanceof ConstructorInfo) {
475       ConstructorInfo constructorMetaData = (ConstructorInfo) data;
476       if (node.getDeclaringTypePattern().matchType(constructorMetaData.getDeclaringType())
477               && visitModifiers(node, constructorMetaData)
478               && visitParameters(node, constructorMetaData.getParameterTypes())) {
479         return Boolean.TRUE;
480       }
481     }
482     return Boolean.FALSE;
483   }
484
485   public Object JavaDoc visit(ASTFieldPattern node, Object JavaDoc data) {
486     if (data instanceof FieldInfo) {
487       FieldInfo fieldInfo = (FieldInfo) data;
488       if (node.getFieldNamePattern().matches(fieldInfo.getName())
489               && node.getDeclaringTypePattern().matchType(fieldInfo.getDeclaringType())
490               && node.getFieldTypePattern().matchType(fieldInfo.getType())
491               && visitModifiers(node, fieldInfo)) {
492         return Boolean.TRUE;
493       }
494     }
495     return Boolean.FALSE;
496   }
497
498   public Object JavaDoc visit(ASTParameter node, Object JavaDoc data) {
499     ClassInfo parameterType = (ClassInfo) data;
500     if (node.getDeclaringClassPattern().matchType(parameterType)) {
501       return Boolean.TRUE;
502     } else {
503       return Boolean.FALSE;
504     }
505   }
506
507   public Object JavaDoc visit(ASTArgs node, Object JavaDoc data) {
508     ExpressionContext ctx = (ExpressionContext) data;
509     if (node.jjtGetNumChildren() <= 0) {
510       // args(EMPTY)
511
return (getParametersCount(ctx) == 0) ? Boolean.TRUE : Boolean.FALSE;
512     } else {
513       // check for ".." as first node
514
int expressionParameterCount = node.jjtGetNumChildren();// the number of node minus eager one.
515
boolean isFirstArgEager = ((ASTArgParameter) node.jjtGetChild(0)).getTypePattern().isEagerWildCard();
516       boolean isLastArgEager = ((ASTArgParameter) node.jjtGetChild(node.jjtGetNumChildren() - 1))
517               .getTypePattern().isEagerWildCard();
518       // args(..)
519
if (isFirstArgEager && expressionParameterCount == 1) {
520         return Boolean.TRUE;
521       }
522       int contextParametersCount = getParametersCount(ctx);
523       if (isFirstArgEager && isLastArgEager) {
524         expressionParameterCount -= 2;
525         if (expressionParameterCount == 0) {
526           // expression is "args(.., ..)"
527
return Boolean.TRUE;
528         }
529         // we need to find a starting position - args(..,int, bar, ..)
530
// foo(int) //int is ok
531
// foo(bar,int,bar) //int is ok
532
// foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
533
int matchCount = 0;
534         int ictx = 0;
535         for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
536           if (ictx >= contextParametersCount) {
537             // too many args in args()
538
matchCount = -1;
539             break;
540           }
541           ctx.setCurrentTargetArgsIndex(ictx);
542           // do we have an eager wildcard in the middle ?
543
boolean isEager = ((ASTArgParameter) node.jjtGetChild(iexp + 1)).getTypePattern().isEagerWildCard();
544           if (isEager) {
545             // TODO - ignore for now, but not really supported - eager in the middle will match one
546
}
547           if (Boolean.TRUE.equals(node.jjtGetChild(iexp + 1).jjtAccept(this, ctx))) {
548             matchCount += 1;
549             ictx++;
550           } else {
551             // assume matched by starting ".." and rewind expression index
552
matchCount = 0;
553             ictx++;
554             iexp = -1;
555           }
556         }
557         if (matchCount == expressionParameterCount) {
558           return Boolean.TRUE;
559         } else {
560           return Boolean.FALSE;
561         }
562       } else if (isFirstArgEager) {
563         expressionParameterCount--;
564         if (contextParametersCount >= expressionParameterCount) {
565           // do a match from last to first, break when args() nodes are exhausted
566
for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
567             ctx.setCurrentTargetArgsIndex(contextParametersCount - 1 - i);
568             if (Boolean.TRUE.equals(
569                     node.jjtGetChild(expressionParameterCount - i).jjtAccept(
570                             this,
571                             ctx
572                     )
573             )) {
574               //go on with "next" arg
575
} else {
576               return Boolean.FALSE;
577             }
578           }
579           return Boolean.TRUE;
580         } else {
581           //args() as more args than context we try to match
582
return Boolean.FALSE;
583         }
584       } else if (isLastArgEager) {
585         expressionParameterCount--;
586         if (contextParametersCount >= expressionParameterCount) {
587           // do a match from first to last, break when args() nodes are exhausted
588
for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
589             ctx.setCurrentTargetArgsIndex(i);
590             if (Boolean.TRUE.equals(node.jjtGetChild(i).jjtAccept(this, ctx))) {
591               //go on with next arg
592
} else {
593               return Boolean.FALSE;
594             }
595           }
596           return Boolean.TRUE;
597         } else {
598           return Boolean.FALSE;
599         }
600       } else {
601         // no eager wildcard in args()
602
// check that args length are equals
603
if (expressionParameterCount == contextParametersCount) {
604           for (int i = 0; i < node.jjtGetNumChildren(); i++) {
605             ctx.setCurrentTargetArgsIndex(i);
606             if (Boolean.TRUE.equals(node.jjtGetChild(i).jjtAccept(this, ctx))) {
607               //go on with next arg
608
} else {
609               return Boolean.FALSE;
610             }
611           }
612           return Boolean.TRUE;
613         } else {
614           return Boolean.FALSE;
615         }
616       }
617     }
618   }
619
620   public Object JavaDoc visit(ASTArgParameter node, Object JavaDoc data) {
621     //TODO we are not doing any hierarchical test when the arg is bound
622
// => args(e) and before(Exception e) will not mathch on catch(SubException e) ..
623
// is that required ? how AJ syntax behaves ?
624

625     TypePattern typePattern = node.getTypePattern();
626     TypePattern realPattern = typePattern;
627
628     // check if the arg is in the pointcut signature. In such a case, use the declared type
629
//TODO can we improve that with a lazy attach of the realTypePattern to the node
630
// and a method that always return the real pattern
631
// It must be lazy since args are not added at info ctor time [can be refactored..]
632
// do some filtering first to avoid unnecessary map lookup
633

634     // int pointcutArgIndex = -1;
635
if (typePattern.getPattern().indexOf(".") < 0) {
636       String JavaDoc boundedType = m_expressionInfo.getArgumentType(typePattern.getPattern());
637       if (boundedType != null) {
638         // pointcutArgIndex = m_expressionInfo.getArgumentIndex(typePattern.getPattern());
639
realPattern = Pattern.compileTypePattern(boundedType, SubtypePatternType.NOT_HIERARCHICAL);
640       }
641     }
642     // grab parameter from context
643
ExpressionContext ctx = (ExpressionContext) data;
644     ClassInfo argInfo = null;
645     try {
646       if (ctx.getReflectionInfo() instanceof MethodInfo) {
647         argInfo = ((MethodInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx.getCurrentTargetArgsIndex()];
648       } else if (ctx.getReflectionInfo() instanceof ConstructorInfo) {
649         argInfo = ((ConstructorInfo) ctx.getReflectionInfo()).getParameterTypes()[ctx
650                 .getCurrentTargetArgsIndex()];
651       } else if (ctx.getReflectionInfo() instanceof FieldInfo) {
652         argInfo = ((FieldInfo) ctx.getReflectionInfo()).getType();
653       } else if (ctx.getPointcutType().equals(PointcutType.HANDLER) && ctx.getReflectionInfo() instanceof ClassInfo) {
654         argInfo = (ClassInfo) ctx.getReflectionInfo();
655       } else {
656         System.err.println("Assigning a null argInfo");
657       }
658     } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
659       System.err.println("ExpressionContext args are exhausted.");
660       return Boolean.FALSE;
661     }
662     if (realPattern.matchType(argInfo)) {
663       return Boolean.TRUE;
664     } else {
665       return Boolean.FALSE;
666     }
667   }
668
669   public Object JavaDoc visit(ASTAttribute node, Object JavaDoc data) {
670     boolean matchAnnotation = false;
671     AnnotationElement.Annotation[] annotations = (AnnotationElement.Annotation[]) data;
672     for (int i = 0; i < annotations.length; i++) {
673       AnnotationElement.Annotation annotation = annotations[i];
674       if (annotation.getInterfaceName().equals(node.getName())) {
675         matchAnnotation = true;
676       }
677     }
678
679     if (node.isNot()) {
680       return Util.booleanValueOf(!matchAnnotation);
681     } else {
682       return Util.booleanValueOf(matchAnnotation);
683     }
684   }
685
686   public Object JavaDoc visit(ASTModifier node, Object JavaDoc data) {
687     ReflectionInfo refInfo = (ReflectionInfo) data;
688     int modifiersToMatch = refInfo.getModifiers();
689     int modifierPattern = node.getModifier();
690     if (node.isNot()) {
691       if ((modifierPattern & Modifier.PUBLIC) != 0) {
692         if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
693           return Boolean.TRUE;
694         } else {
695           return Boolean.FALSE;
696         }
697       } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
698         if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
699           return Boolean.TRUE;
700         } else {
701           return Boolean.FALSE;
702         }
703       } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
704         if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
705           return Boolean.TRUE;
706         } else {
707           return Boolean.FALSE;
708         }
709       } else if ((modifierPattern & Modifier.STATIC) != 0) {
710         if ((modifiersToMatch & Modifier.STATIC) == 0) {
711           return Boolean.TRUE;
712         } else {
713           return Boolean.FALSE;
714         }
715       } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
716         if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
717           return Boolean.TRUE;
718         } else {
719           return Boolean.FALSE;
720         }
721       } else if ((modifierPattern & Modifier.FINAL) != 0) {
722         if ((modifiersToMatch & Modifier.FINAL) == 0) {
723           return Boolean.TRUE;
724         } else {
725           return Boolean.FALSE;
726         }
727       } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
728         if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
729           return Boolean.TRUE;
730         } else {
731           return Boolean.FALSE;
732         }
733       } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
734         if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
735           return Boolean.TRUE;
736         } else {
737           return Boolean.FALSE;
738         }
739       } else if ((modifierPattern & Modifier.STRICT) != 0) {
740         if ((modifiersToMatch & Modifier.STRICT) == 0) {
741           return Boolean.TRUE;
742         } else {
743           return Boolean.FALSE;
744         }
745       } else {
746         return Boolean.FALSE;
747       }
748     } else {
749       if ((modifierPattern & Modifier.PUBLIC) != 0) {
750         if (((modifiersToMatch & Modifier.PUBLIC) == 0)) {
751           return Boolean.FALSE;
752         } else {
753           return Boolean.TRUE;
754         }
755       } else if ((modifierPattern & Modifier.PROTECTED) != 0) {
756         if ((modifiersToMatch & Modifier.PROTECTED) == 0) {
757           return Boolean.FALSE;
758         } else {
759           return Boolean.TRUE;
760         }
761       } else if ((modifierPattern & Modifier.PRIVATE) != 0) {
762         if ((modifiersToMatch & Modifier.PRIVATE) == 0) {
763           return Boolean.FALSE;
764         } else {
765           return Boolean.TRUE;
766         }
767       } else if ((modifierPattern & Modifier.STATIC) != 0) {
768         if ((modifiersToMatch & Modifier.STATIC) == 0) {
769           return Boolean.FALSE;
770         } else {
771           return Boolean.TRUE;
772         }
773       } else if ((modifierPattern & Modifier.SYNCHRONIZED) != 0) {
774         if ((modifiersToMatch & Modifier.SYNCHRONIZED) == 0) {
775           return Boolean.FALSE;
776         } else {
777           return Boolean.TRUE;
778         }
779       } else if ((modifierPattern & Modifier.FINAL) != 0) {
780         if ((modifiersToMatch & Modifier.FINAL) == 0) {
781           return Boolean.FALSE;
782         } else {
783           return Boolean.TRUE;
784         }
785       } else if ((modifierPattern & Modifier.TRANSIENT) != 0) {
786         if ((modifiersToMatch & Modifier.TRANSIENT) == 0) {
787           return Boolean.FALSE;
788         } else {
789           return Boolean.TRUE;
790         }
791       } else if ((modifierPattern & Modifier.VOLATILE) != 0) {
792         if ((modifiersToMatch & Modifier.VOLATILE) == 0) {
793           return Boolean.FALSE;
794         } else {
795           return Boolean.TRUE;
796         }
797       } else if ((modifierPattern & Modifier.STRICT) != 0) {
798         if ((modifiersToMatch & Modifier.STRICT) == 0) {
799           return Boolean.FALSE;
800         } else {
801           return Boolean.TRUE;
802         }
803       } else {
804         return Boolean.TRUE;
805       }
806     }
807   }
808
809   protected boolean visitAttributes(SimpleNode node, ReflectionInfo refInfo) {
810     int nrChildren = node.jjtGetNumChildren();
811     if (nrChildren != 0) {
812       for (int i = 0; i < nrChildren; i++) {
813         Node child = node.jjtGetChild(i);
814         if (child instanceof ASTAttribute) {
815           if (Boolean.TRUE.equals(child.jjtAccept(this, refInfo.getAnnotations()))) {
816             continue;
817           } else {
818             return false;
819           }
820         }
821       }
822     }
823     return true;
824   }
825
826   protected boolean visitModifiers(SimpleNode node, ReflectionInfo refInfo) {
827     int nrChildren = node.jjtGetNumChildren();
828     if (nrChildren != 0) {
829       for (int i = 0; i < nrChildren; i++) {
830         Node child = node.jjtGetChild(i);
831         if (child instanceof ASTModifier) {
832           if (Boolean.TRUE.equals(child.jjtAccept(this, refInfo))) {
833             continue;
834           } else {
835             return false;
836           }
837         }
838       }
839     }
840     return true;
841   }
842
843   protected boolean visitParameters(SimpleNode node, ClassInfo[] parameterTypes) {
844     int nrChildren = node.jjtGetNumChildren();
845     if (nrChildren <= 0) {
846       return (parameterTypes.length == 0);
847     }
848
849     // collect the parameter nodes
850
List JavaDoc parameterNodes = new ArrayList JavaDoc();
851     for (int i = 0; i < nrChildren; i++) {
852       Node child = node.jjtGetChild(i);
853       if (child instanceof ASTParameter) {
854         parameterNodes.add(child);
855       }
856     }
857
858     if (parameterNodes.size() <= 0) {
859       return (parameterTypes.length == 0);
860     }
861
862     //TODO duplicate code with args() match
863
//TODO refactor parameterNodes in an array for faster match
864

865     // look for eager pattern at the beginning and end
866
int expressionParameterCount = parameterNodes.size();
867     boolean isFirstArgEager = ((ASTParameter) parameterNodes.get(0)).getDeclaringClassPattern().isEagerWildCard();
868     boolean isLastArgEager = ((ASTParameter) parameterNodes.get(expressionParameterCount - 1)).getDeclaringClassPattern()
869             .isEagerWildCard();
870     // foo(..)
871
if (isFirstArgEager && expressionParameterCount == 1) {
872       return true;
873     }
874     int contextParametersCount = parameterTypes.length;
875     if (isFirstArgEager && isLastArgEager) {
876       expressionParameterCount -= 2;
877       if (expressionParameterCount == 0) {
878         // foo(.., ..)
879
return true;
880       }
881       // we need to find a starting position - foo(..,int, bar, ..)
882
// foo(int) //int is ok
883
// foo(bar,int,bar) //int is ok
884
// foo(bar,int,foo,int,bar) // int is ok, but then we fail, so move on to next..
885
int matchCount = 0;
886       int ictx = 0;
887       for (int iexp = 0; iexp < expressionParameterCount; iexp++) {
888         if (ictx >= contextParametersCount) {
889           // too many args in foo()
890
matchCount = -1;
891           break;
892         }
893         // do we have an eager wildcard in the middle ?
894
ASTParameter parameterNode = (ASTParameter) parameterNodes.get(iexp + 1);
895         boolean isEager = parameterNode.getDeclaringClassPattern().isEagerWildCard();
896         if (isEager) {
897           // TODO - ignore for now, but not really supported - eager in the middle will match one
898
}
899         if (Boolean.TRUE.equals(parameterNode.jjtAccept(this, parameterTypes[ictx]))) {
900           matchCount += 1;
901           ictx++;
902         } else {
903           // assume matched by starting ".." and rewind expression index
904
matchCount = 0;
905           ictx++;
906           iexp = -1;
907         }
908       }
909       if (matchCount == expressionParameterCount) {
910         return true;
911       } else {
912         return false;
913       }
914     } else if (isFirstArgEager) {
915       expressionParameterCount--;
916       if (contextParametersCount >= expressionParameterCount) {
917         // do a match from last to first, break when foo() nodes are exhausted
918
for (int i = 0; (i < contextParametersCount) && (expressionParameterCount - i >= 0); i++) {
919           ASTParameter parameterNode = (ASTParameter) parameterNodes.get(expressionParameterCount - i);
920           if (Boolean.TRUE.equals(
921                   parameterNode.jjtAccept(
922                           this,
923                           parameterTypes[contextParametersCount - 1 - i]
924                   )
925           )) {
926             //go on with "next" param
927
} else {
928             return false;
929           }
930         }
931         return true;
932       } else {
933         //foo() as more param than context we try to match
934
return false;
935       }
936     } else if (isLastArgEager) {
937       expressionParameterCount--;
938       if (contextParametersCount >= expressionParameterCount) {
939         // do a match from first to last, break when foo() nodes are exhausted
940
for (int i = 0; (i < contextParametersCount) && (i < expressionParameterCount); i++) {
941           ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
942           if (Boolean.TRUE.equals(parameterNode.jjtAccept(this, parameterTypes[i]))) {
943             //go on with next param
944
} else {
945             return false;
946           }
947         }
948         return true;
949       } else {
950         return false;
951       }
952     } else {
953       // no eager wildcard in foo()
954
// check that param length are equals
955
if (expressionParameterCount == contextParametersCount) {
956         for (int i = 0; i < parameterNodes.size(); i++) {
957           ASTParameter parameterNode = (ASTParameter) parameterNodes.get(i);
958           if (Boolean.TRUE.equals(parameterNode.jjtAccept(this, parameterTypes[i]))) {
959             //go on with next param
960
} else {
961             return false;
962           }
963         }
964         return true;
965       } else {
966         return false;
967       }
968     }
969   }
970
971   /**
972    * Returns the string representation of the expression.
973    *
974    * @return
975    */

976   public String JavaDoc toString() {
977     return m_expression;
978   }
979
980   /**
981    * Returns the number of parameters to the target method/constructor else -1.
982    *
983    * @param ctx
984    * @return
985    */

986   private int getParametersCount(final ExpressionContext ctx) {
987     ReflectionInfo reflectionInfo = ctx.getReflectionInfo();
988     if (reflectionInfo instanceof MethodInfo) {
989       return ((MethodInfo) reflectionInfo).getParameterTypes().length;
990     } else if (reflectionInfo instanceof ConstructorInfo) {
991       return ((ConstructorInfo) reflectionInfo).getParameterTypes().length;
992     } else if (reflectionInfo instanceof FieldInfo) {
993       return 1;//field set support for args()
994
} else if (ctx.getPointcutType().equals(PointcutType.HANDLER) && reflectionInfo instanceof ClassInfo) {
995       // handler args(e) binding
996
return 1;
997     } else {
998       return -1;
999     }
1000  }
1001
1002  /**
1003   * Test the context upon the expression tree, under a node that can
1004   * contain annotations.
1005   *
1006   * @param node root node of the annotation expression
1007   * @param reflectInfo context reflection info
1008   * @return <CODE>Boolean.TRUE</CODE> in case the <tt>reflectInfo</tt> match
1009   * the expression subtree, <CODE>Boolean.FALSE</CODE> otherwise.
1010   */

1011  protected Object JavaDoc visitAnnotatedNode(SimpleNode node,
1012                                      ReflectionInfo reflectInfo) {
1013    // In an annotated subtree, only the last child node may represent the pattern
1014
Node patternNode = node.jjtGetChild(node.jjtGetNumChildren() - 1);
1015    if (!(patternNode instanceof ASTAttribute)) {
1016      if (Boolean.FALSE.equals(patternNode.jjtAccept(this, reflectInfo))) {
1017        return Boolean.FALSE;
1018      }
1019    }
1020
1021    boolean matchedAnnotations = visitAttributes(node, reflectInfo);
1022    if (!matchedAnnotations) {
1023      return Boolean.FALSE;
1024    } else {
1025      return Boolean.TRUE;
1026    }
1027  }
1028
1029  /**
1030   * Access the ASTRoot we visit
1031   *
1032   * @return
1033   */

1034  public Node getASTRoot() {
1035    return m_root;
1036  }
1037
1038  /**
1039   * Access the ExpressionInfo we are build on
1040   *
1041   * @return
1042   */

1043  public ExpressionInfo getExpressionInfo() {
1044    return m_expressionInfo;
1045  }
1046}
1047
Popular Tags