1 /***************************************************************************************
2 * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.expression;
9
10 import org.codehaus.aspectwerkz.expression.ast.ASTAnd;
11 import org.codehaus.aspectwerkz.expression.ast.ASTAttribute;
12 import org.codehaus.aspectwerkz.expression.ast.ASTCall;
13 import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
14 import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
15 import org.codehaus.aspectwerkz.expression.ast.ASTClassPattern;
16 import org.codehaus.aspectwerkz.expression.ast.ASTConstructorPattern;
17 import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
18 import org.codehaus.aspectwerkz.expression.ast.ASTExpression;
19 import org.codehaus.aspectwerkz.expression.ast.ASTFieldPattern;
20 import org.codehaus.aspectwerkz.expression.ast.ASTGet;
21 import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
22 import org.codehaus.aspectwerkz.expression.ast.ASTMethodPattern;
23 import org.codehaus.aspectwerkz.expression.ast.ASTModifier;
24 import org.codehaus.aspectwerkz.expression.ast.ASTNot;
25 import org.codehaus.aspectwerkz.expression.ast.ASTOr;
26 import org.codehaus.aspectwerkz.expression.ast.ASTParameter;
27 import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
28 import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
29 import org.codehaus.aspectwerkz.expression.ast.ASTSet;
30 import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
31 import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
32 import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
33 import org.codehaus.aspectwerkz.expression.ast.ExpressionParserVisitor;
34 import org.codehaus.aspectwerkz.expression.ast.Node;
35 import org.codehaus.aspectwerkz.expression.ast.SimpleNode;
36 import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
37 import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
38 import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
39 import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
40 import org.codehaus.aspectwerkz.expression.regexp.TypePattern;
41 import org.codehaus.aspectwerkz.reflect.ClassInfo;
42 import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
43 import org.codehaus.aspectwerkz.reflect.MemberInfo;
44 import org.codehaus.aspectwerkz.reflect.ReflectionInfo;
45 import org.codehaus.aspectwerkz.reflect.MethodInfo;
46 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
47 import org.codehaus.aspectwerkz.reflect.FieldInfo;
48 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
49
50 import java.util.List;
51 import java.util.Iterator;
52
53 /***
54 * The advised class filter visitor.
55 *
56 * Visit() methods are returning Boolean.TRUE/FALSE or null when decision cannot be taken.
57 * Using null allow composition of OR/AND with NOT in the best way.
58 *
59 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
60 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
61 * @author Michael Nascimento
62 */
63 public class AdvisedClassFilterExpressionVisitor implements ExpressionParserVisitor {
64 protected final ASTRoot m_root;
65
66 protected final String m_expression;
67
68 protected final String m_namespace;
69
70 /***
71 * Creates a new expression.
72 *
73 * @param expression the expression as a string
74 * @param namespace the namespace
75 * @param root the AST root
76 */
77 public AdvisedClassFilterExpressionVisitor(final String expression, final String namespace, final ASTRoot root) {
78 m_root = root;
79 m_expression = expression;
80 m_namespace = namespace;
81 }
82
83 /***
84 * Matches the expression context.
85 *
86 * @param context
87 * @return
88 */
89 public boolean match(final ExpressionContext context) {
90 Boolean match = ((Boolean) visit(m_root, context));
91
92
93
94 return (match != null)?match.booleanValue():true;
95 }
96
97
98 public Object visit(SimpleNode node, Object data) {
99 return node.jjtGetChild(0).jjtAccept(this, data);
100 }
101
102 public Object visit(ASTRoot node, Object data) {
103 Node child = node.jjtGetChild(0);
104
105
106
107
108
109 Boolean match = (Boolean) child.jjtAccept(this, data);
110 return match;
111 }
112
113 public Object visit(ASTExpression node, Object data) {
114 Node child = node.jjtGetChild(0);
115
116
117
118
119
120 Boolean match = (Boolean) child.jjtAccept(this, data);
121 return match;
122 }
123
124
125 public Object visit(ASTOr node, Object data) {
126 Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
127 Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
128 Boolean intermediate = matchUndeterministicOr(matchL, matchR);
129 for (int i = 2; i < node.jjtGetNumChildren(); i++) {
130 Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
131 intermediate = matchUndeterministicOr(intermediate, matchNext);
132 }
133 return intermediate;
134 }
135
136 public Object visit(ASTAnd node, Object data) {
137
138 Boolean matchL = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
139 Boolean matchR = (Boolean) node.jjtGetChild(1).jjtAccept(this, data);
140 Boolean intermediate = matchUnderterministicAnd(matchL, matchR);
141 for (int i = 2; i < node.jjtGetNumChildren(); i++) {
142 Boolean matchNext = (Boolean) node.jjtGetChild(i).jjtAccept(this, data);
143 intermediate = matchUnderterministicAnd(intermediate, matchNext);
144 }
145 return intermediate;
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 }
189
190 public Object visit(ASTNot node, Object data) {
191
192
193
194
195
196
197
198
199
200
201 Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
202 if (match !=null) {
203
204 if (match.equals(Boolean.TRUE)) {
205 return Boolean.FALSE;
206 } else {
207 return Boolean.TRUE;
208 }
209 } else {
210 return null;
211 }
212 }
213
214
215 public Object visit(ASTPointcutReference node, Object data) {
216 ExpressionContext context = (ExpressionContext) data;
217 ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
218 AdvisedClassFilterExpressionVisitor expression = namespace.getAdvisedClassExpression(node.getName());
219 return new Boolean(expression.match(context));
220 }
221
222 public Object visit(ASTExecution node, Object data) {
223 ExpressionContext context = (ExpressionContext) data;
224
225 if (context.hasWithinPointcut() || context.hasExecutionPointcut()) {
226 return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
227 } else {
228 return Boolean.FALSE;
229 }
230 }
231
232 public Object visit(ASTCall node, Object data) {
233 ExpressionContext context = (ExpressionContext) data;
234
235 if (context.hasWithinPointcut() || context.hasCallPointcut()) {
236 if (context.hasReflectionInfo()) {
237 return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
238 } else {
239 return null;
240 }
241 } else {
242 return Boolean.FALSE;
243 }
244 }
245
246 public Object visit(ASTSet node, Object data) {
247 ExpressionContext context = (ExpressionContext) data;
248
249
250 if (context.hasWithinPointcut() || context.hasSetPointcut()) {
251 if (context.hasReflectionInfo()) {
252 return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
253 } else {
254 return null;
255 }
256 } else {
257 return Boolean.FALSE;
258 }
259 }
260
261 public Object visit(ASTGet node, Object data) {
262 ExpressionContext context = (ExpressionContext) data;
263
264
265 if (context.hasWithinPointcut() || context.hasGetPointcut()) {
266 if (context.hasReflectionInfo()) {
267 return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
268 } else {
269 return null;
270 }
271 } else {
272 return Boolean.FALSE;
273 }
274 }
275
276 public Object visit(ASTHandler node, Object data) {
277
278 return Boolean.TRUE;
279 }
280
281 public Object visit(ASTStaticInitialization node, Object data) {
282 ExpressionContext context = (ExpressionContext) data;
283 if (context.hasWithinPointcut() || context.hasStaticInitializationPointcut()) {
284 return node.jjtGetChild(0).jjtAccept(this, context.getReflectionInfo());
285 } else {
286 return Boolean.FALSE;
287 }
288 }
289
290 public Object visit(ASTWithin node, Object data) {
291 ExpressionContext context = (ExpressionContext) data;
292 ReflectionInfo reflectionInfo = context.getWithinReflectionInfo();
293 if (reflectionInfo instanceof MemberInfo) {
294 return node.jjtGetChild(0).jjtAccept(this, ((MemberInfo) reflectionInfo).getDeclaringType());
295 } else if (reflectionInfo instanceof ClassInfo) {
296 return node.jjtGetChild(0).jjtAccept(this, reflectionInfo);
297 } else {
298 return Boolean.FALSE;
299 }
300 }
301
302 public Object visit(ASTWithinCode node, Object data) {
303 ExpressionContext context = (ExpressionContext) data;
304 return node.jjtGetChild(0).jjtAccept(this, context.getWithinReflectionInfo());
305 }
306
307 public Object visit(ASTCflow node, Object data) {
308 return null;
309 }
310
311 public Object visit(ASTCflowBelow node, Object data) {
312 return null;
313 }
314
315 public Object visit(ASTArgs node, Object data) {
316 return null;
317 }
318
319 public Object visit(ASTHasMethod node, Object data) {
320 ExpressionContext context = (ExpressionContext) data;
321 return node.jjtGetChild(0).jjtAccept(this, context.getWithinReflectionInfo());
322 }
323
324 public Object visit(ASTHasField node, Object data) {
325 ExpressionContext context = (ExpressionContext) data;
326 return node.jjtGetChild(0).jjtAccept(this, context.getWithinReflectionInfo());
327 }
328
329
330 public Object visit(ASTClassPattern node, Object data) {
331 ClassInfo classInfo = (ClassInfo) data;
332 TypePattern typePattern = node.getTypePattern();
333 if (ClassInfoHelper.matchType(typePattern, classInfo) && visitAttributes(node, classInfo)) {
334 return Boolean.TRUE;
335 } else {
336 return Boolean.FALSE;
337 }
338 }
339
340 public Object visit(ASTMethodPattern node, Object data) {
341 if (data instanceof ClassInfo) {
342 ClassInfo classInfo = (ClassInfo) data;
343 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), classInfo)) {
344 return Boolean.TRUE;
345 }
346 return Boolean.FALSE;
347 } else if (data instanceof MethodInfo) {
348 MethodInfo methodInfo = (MethodInfo) data;
349 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), methodInfo.getDeclaringType())) {
350 return null;
351 }
352 return Boolean.FALSE;
353 }
354 return Boolean.FALSE;
355 }
356
357 public Object visit(ASTConstructorPattern node, Object data) {
358 if (data instanceof ClassInfo) {
359 ClassInfo classInfo = (ClassInfo) data;
360 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), classInfo)) {
361
362 return Boolean.TRUE;
363 }
364 } else if (data instanceof ConstructorInfo) {
365 ConstructorInfo constructorInfo = (ConstructorInfo) data;
366 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), constructorInfo.getDeclaringType())) {
367 return null;
368 }
369 return Boolean.FALSE;
370 }
371 return Boolean.FALSE;
372 }
373
374 public Object visit(ASTFieldPattern node, Object data) {
375 if (data instanceof ClassInfo) {
376 ClassInfo classInfo = (ClassInfo) data;
377 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), classInfo)) {
378
379 return Boolean.TRUE;
380 }
381 } else if (data instanceof FieldInfo) {
382 FieldInfo fieldInfo = (FieldInfo) data;
383 if (ClassInfoHelper.matchType(node.getDeclaringTypePattern(), fieldInfo.getDeclaringType())) {
384 return null;
385 }
386 return Boolean.FALSE;
387 }
388 return Boolean.FALSE;
389 }
390
391 public Object visit(ASTParameter node, Object data) {
392 ClassInfo parameterType = (ClassInfo) data;
393 if (ClassInfoHelper.matchType(node.getDeclaringClassPattern(), parameterType)) {
394
395 return Boolean.TRUE;
396 } else {
397 return Boolean.FALSE;
398 }
399 }
400
401 public Object visit(ASTArgParameter node, Object data) {
402
403 return Boolean.TRUE;
404 }
405
406 public Object visit(ASTAttribute node, Object data) {
407
408 List annotations = (List) data;
409 for (Iterator it = annotations.iterator(); it.hasNext();) {
410 AnnotationInfo annotation = (AnnotationInfo) it.next();
411 if (annotation.getName().equals(node.getName())) {
412 return Boolean.TRUE;
413 }
414 }
415 return Boolean.FALSE;
416 }
417
418 public Object visit(ASTModifier node, Object data) {
419
420 return null;
421 }
422
423 /***
424 * Returns the string representation of the AST.
425 *
426 * @return
427 */
428 public String toString() {
429 return m_expression;
430 }
431
432 protected boolean visitAttributes(SimpleNode node, ReflectionInfo refInfo) {
433 int nrChildren = node.jjtGetNumChildren();
434 if (nrChildren != 0) {
435 for (int i = 0; i < nrChildren; i++) {
436 Node child = node.jjtGetChild(i);
437 if (child instanceof ASTAttribute) {
438 List annotations = refInfo.getAnnotations();
439 if (Boolean.TRUE.equals(child.jjtAccept(this, annotations))) {
440 continue;
441 } else {
442 return false;
443 }
444 }
445 }
446 }
447 return true;
448 }
449
450 private static Boolean matchUnderterministicAnd(Boolean lhs, Boolean rhs) {
451 if (lhs != null && rhs !=null) {
452
453 if (lhs.equals(Boolean.TRUE) && rhs.equals(Boolean.TRUE)) {
454 return Boolean.TRUE;
455 } else {
456 return Boolean.FALSE;
457 }
458 } else if (lhs != null && lhs.equals(Boolean.FALSE)) {
459
460 return Boolean.FALSE;
461 } else if (rhs != null && rhs.equals(Boolean.FALSE)) {
462
463 return Boolean.FALSE;
464 } else {
465
466 return null;
467 }
468 }
469
470 private static Boolean matchUndeterministicOr(Boolean lhs, Boolean rhs) {
471 if (lhs != null && rhs !=null) {
472
473 if (lhs.equals(Boolean.TRUE) || rhs.equals(Boolean.TRUE)) {
474 return Boolean.TRUE;
475 } else {
476 return Boolean.FALSE;
477 }
478 } else {
479
480
481 return null;
482 }
483 }
484 }