001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.expression;
005:
006: import com.tc.backport175.bytecode.AnnotationElement;
007:
008: import com.tc.aspectwerkz.expression.ast.ASTArgParameter;
009: import com.tc.aspectwerkz.expression.ast.ASTArgs;
010: import com.tc.aspectwerkz.expression.ast.ASTAttribute;
011: import com.tc.aspectwerkz.expression.ast.ASTCall;
012: import com.tc.aspectwerkz.expression.ast.ASTCflow;
013: import com.tc.aspectwerkz.expression.ast.ASTCflowBelow;
014: import com.tc.aspectwerkz.expression.ast.ASTConstructorPattern;
015: import com.tc.aspectwerkz.expression.ast.ASTExecution;
016: import com.tc.aspectwerkz.expression.ast.ASTExpression;
017: import com.tc.aspectwerkz.expression.ast.ASTFieldPattern;
018: import com.tc.aspectwerkz.expression.ast.ASTGet;
019: import com.tc.aspectwerkz.expression.ast.ASTHandler;
020: import com.tc.aspectwerkz.expression.ast.ASTMethodPattern;
021: import com.tc.aspectwerkz.expression.ast.ASTModifier;
022: import com.tc.aspectwerkz.expression.ast.ASTNot;
023: import com.tc.aspectwerkz.expression.ast.ASTParameter;
024: import com.tc.aspectwerkz.expression.ast.ASTPointcutReference;
025: import com.tc.aspectwerkz.expression.ast.ASTRoot;
026: import com.tc.aspectwerkz.expression.ast.ASTSet;
027: import com.tc.aspectwerkz.expression.ast.ASTStaticInitialization;
028: import com.tc.aspectwerkz.expression.ast.ASTTarget;
029: import com.tc.aspectwerkz.expression.ast.ASTThis;
030: import com.tc.aspectwerkz.expression.ast.ASTWithin;
031: import com.tc.aspectwerkz.expression.ast.ASTWithinCode;
032: import com.tc.aspectwerkz.expression.ast.ExpressionParserVisitor;
033: import com.tc.aspectwerkz.expression.ast.Node;
034: import com.tc.aspectwerkz.expression.ast.SimpleNode;
035: import com.tc.aspectwerkz.util.Util;
036: import com.tc.aspectwerkz.reflect.StaticInitializationInfo;
037: import com.tc.aspectwerkz.reflect.ReflectionInfo;
038: import com.tc.aspectwerkz.reflect.ClassInfo;
039: import com.tc.aspectwerkz.reflect.MemberInfo;
040: import com.tc.aspectwerkz.reflect.ClassInfoHelper;
041: import com.tc.aspectwerkz.reflect.MethodInfo;
042: import com.tc.aspectwerkz.reflect.FieldInfo;
043: import com.tc.aspectwerkz.reflect.ConstructorInfo;
044:
045: /**
046: * The advised class filter visitor.
047: * <p/>
048: * Visit() methods are returning Boolean.TRUE/FALSE or null when decision cannot be taken.
049: * Using null allow composition of OR/AND with NOT in the best way.
050: *
051: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
052: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
053: * @author Michael Nascimento
054: * @author <a href="mailto:the_mindstorm@evolva.ro">Alex Popescu</a>
055: */
056: public class AdvisedClassFilterExpressionVisitor extends
057: ExpressionVisitor implements ExpressionParserVisitor {
058:
059: /**
060: * Creates a new expression.
061: *
062: * @param expression the expression as a string
063: * @param namespace the namespace
064: * @param root the AST root
065: */
066: public AdvisedClassFilterExpressionVisitor(
067: final ExpressionInfo expressionInfo,
068: final String expression, final String namespace,
069: final Node root) {
070: super (expressionInfo, expression, namespace, root);
071: }
072:
073: // ============ Boot strap =============
074: public Object visit(SimpleNode node, Object data) {
075: return node.jjtGetChild(0).jjtAccept(this , data);
076: }
077:
078: public Object visit(ASTRoot node, Object data) {
079: Node child = node.jjtGetChild(0);
080: Boolean match = (Boolean) child.jjtAccept(this , data);
081: return match;
082: }
083:
084: public Object visit(ASTExpression node, Object data) {
085: Node child = node.jjtGetChild(0);
086: Boolean match = (Boolean) child.jjtAccept(this , data);
087: return match;
088: }
089:
090: public Object visit(ASTNot node, Object data) {
091: return super .visit(node, data);
092: }
093:
094: // ============ Pointcut types =============
095: public Object visit(ASTPointcutReference node, Object data) {
096: ExpressionContext context = (ExpressionContext) data;
097: ExpressionNamespace namespace = ExpressionNamespace
098: .getNamespace(m_namespace);
099: AdvisedClassFilterExpressionVisitor expression = namespace
100: .getAdvisedClassExpression(node.getName());
101: return expression.matchUndeterministic(context);
102: }
103:
104: public Object visit(ASTExecution node, Object data) {
105: ExpressionContext context = (ExpressionContext) data;
106:
107: // only the last node might be the pattern, others are annotations
108: Node patternNode = node
109: .jjtGetChild(node.jjtGetNumChildren() - 1);
110: boolean checkPattern = !(patternNode instanceof ASTAttribute);
111:
112: if (checkPattern) {
113: if (context.hasWithinPointcut()
114: || context.hasExecutionPointcut()) {
115: if (context.hasExecutionPointcut()) {
116: // reflectionInfo was given
117: return patternNode.jjtAccept(this , context
118: .getReflectionInfo());
119: } else {
120: // only withinInfo was given
121: return patternNode.jjtAccept(this , context
122: .getWithinReflectionInfo());
123: }
124: } else {
125: return Boolean.FALSE;
126: }
127: } else {
128: return null;
129: }
130: }
131:
132: public Object visit(ASTCall node, Object data) {
133: ExpressionContext context = (ExpressionContext) data;
134:
135: // only the last node might be the pattern, others are annotations
136: Node patternNode = node
137: .jjtGetChild(node.jjtGetNumChildren() - 1);
138: boolean checkPattern = !(patternNode instanceof ASTAttribute);
139:
140: if (checkPattern) {
141: if (context.hasWithinPointcut()
142: || context.hasCallPointcut()) {
143: if (context.hasReflectionInfo()) {
144: return patternNode.jjtAccept(this , context
145: .getReflectionInfo());
146: } else {
147: return null;
148: }
149: } else {
150: return Boolean.FALSE;
151: }
152: } else {
153: return null;
154: }
155: }
156:
157: public Object visit(ASTSet node, Object data) {
158: ExpressionContext context = (ExpressionContext) data;
159:
160: // only the last node might be the pattern, others are annotations
161: Node patternNode = node
162: .jjtGetChild(node.jjtGetNumChildren() - 1);
163: boolean checkPattern = !(patternNode instanceof ASTAttribute);
164:
165: // for set evaluation, the reflection info may be null at the early matching phase
166: // when we will allow for field interception within non declaring class
167: if (checkPattern) {
168: if (context.hasWithinPointcut() || context.hasSetPointcut()) {
169: if (context.hasReflectionInfo()) {
170: return patternNode.jjtAccept(this , context
171: .getReflectionInfo());
172: } else {
173: return null;
174: }
175: } else {
176: return Boolean.FALSE;
177: }
178: } else {
179: return null;
180: }
181: }
182:
183: public Object visit(ASTGet node, Object data) {
184: ExpressionContext context = (ExpressionContext) data;
185:
186: // only the last node might be the pattern, others are annotations
187: Node patternNode = node
188: .jjtGetChild(node.jjtGetNumChildren() - 1);
189: boolean checkPattern = !(patternNode instanceof ASTAttribute);
190:
191: // for getDefault evaluation, the reflection info may be null at the early matching phase
192: // since we allow for field interception within non declaring class
193: if (checkPattern) {
194: if (context.hasWithinPointcut() || context.hasGetPointcut()) {
195: if (context.hasReflectionInfo()) {
196: return patternNode.jjtAccept(this , context
197: .getReflectionInfo());
198: } else {
199: return null;
200: }
201: } else {
202: return Boolean.FALSE;
203: }
204: } else {
205: return null;
206: }
207: }
208:
209: public Object visit(ASTHandler node, Object data) {
210: return null;
211: }
212:
213: public Object visit(ASTStaticInitialization node, Object data) {
214: ExpressionContext context = (ExpressionContext) data;
215:
216: if (context.hasStaticInitializationPointcut()
217: && context.hasWithinReflectionInfo()) {
218: ReflectionInfo reflectInfo = context
219: .getWithinReflectionInfo();
220: if (reflectInfo instanceof StaticInitializationInfo) {
221: reflectInfo = ((StaticInitializationInfo) reflectInfo)
222: .getDeclaringType();
223: }
224: if (reflectInfo instanceof ClassInfo) {
225: // In an annotated subtree, the last child node represents the pattern
226: Node patternNode = node.jjtGetChild(node
227: .jjtGetNumChildren() - 1);
228: if (!(patternNode instanceof ASTAttribute)) {
229: Boolean matchPattern = (Boolean) patternNode
230: .jjtAccept(this , reflectInfo);
231: if (Boolean.FALSE.equals(matchPattern)) {
232: return Boolean.FALSE;
233: }
234: }
235:
236: // match on the annotations since the pattern was not there or matched
237: boolean matchedAnnotations = visitAttributes(node,
238: reflectInfo);
239: if (!matchedAnnotations) {
240: return Boolean.FALSE;
241: } else {
242: return null;//match but early phase
243: }
244: } else {
245: return Boolean.FALSE;
246: }
247: } else {
248: return Boolean.FALSE;
249: }
250: }
251:
252: public Object visit(ASTWithinCode node, Object data) {
253: ExpressionContext context = (ExpressionContext) data;
254: ReflectionInfo withinInfo = context.getWithinReflectionInfo();
255:
256: if (node.isStaticInitializer()) {
257: // transform the node in a within node to do an exact match on the within info
258: //TODO would be worth to do the fastNode creation only once somewhere
259: ASTWithin fastNode = new ASTWithin(0);
260: for (int i = 0; i < node.jjtGetChild(0).jjtGetNumChildren(); i++) {
261: fastNode.jjtAddChild(
262: node.jjtGetChild(0).jjtGetChild(i), i);
263: }
264: return super .visit(fastNode, data);
265: } else {
266: Node patternNode = node.jjtGetChild(node
267: .jjtGetNumChildren() - 1);
268: boolean checkPattern = !(patternNode instanceof ASTAttribute);
269:
270: if (checkPattern) {
271: if (withinInfo instanceof MemberInfo) {
272: return patternNode.jjtAccept(this , withinInfo);
273: } else if (withinInfo instanceof ClassInfo) {
274: Boolean matchDeclaringType = (Boolean) patternNode
275: .jjtAccept(this , withinInfo);
276: if (Boolean.FALSE.equals(matchDeclaringType)) {
277: return Boolean.FALSE;
278: } else {
279: // may be we match now but not later?
280: return null;
281: }
282: } else {
283: return null;
284: }
285: } else {
286: return null;
287: }
288: }
289: }
290:
291: public Object visit(ASTCflow node, Object data) {
292: return null;
293: }
294:
295: public Object visit(ASTCflowBelow node, Object data) {
296: return null;
297: }
298:
299: public Object visit(ASTArgs node, Object data) {
300: return null;
301: }
302:
303: public Object visit(ASTTarget node, Object data) {
304: return null;// is that good enough ? For execution PC we would optimize some
305: }
306:
307: public Object visit(ASTThis node, Object data) {
308: ExpressionContext context = (ExpressionContext) data;
309: if (context.hasWithinReflectionInfo()) {
310: ReflectionInfo withinInfo = context
311: .getWithinReflectionInfo();
312: if (withinInfo instanceof MemberInfo) {
313: return Util.booleanValueOf(ClassInfoHelper.instanceOf(
314: ((MemberInfo) withinInfo).getDeclaringType(),
315: node.getBoundedType(m_expressionInfo)));
316: } else if (withinInfo instanceof ClassInfo) {
317: return Util.booleanValueOf(ClassInfoHelper.instanceOf(
318: (ClassInfo) withinInfo, node
319: .getBoundedType(m_expressionInfo)));
320: }
321: }
322: return Boolean.FALSE;
323: }
324:
325: // ============ Patterns =============
326: // public Object visit(ASTClassPattern node, Object data) {
327: // if(null == data) {
328: // return null;
329: // } else if( !(data instanceof ClassInfo) ) {
330: // return Boolean.FALSE;
331: // }
332: //
333: // ClassInfo classInfo = (ClassInfo) data;
334: // if (node.getTypePattern().matchType(classInfo) && visitAttributes(node, classInfo)) {
335: // return Boolean.TRUE;
336: // } else {
337: // return Boolean.FALSE;
338: // }
339: // }
340:
341: public Object visit(ASTMethodPattern node, Object data) {
342: if (data instanceof ClassInfo) {
343: ClassInfo classInfo = (ClassInfo) data;
344: if (node.getDeclaringTypePattern().matchType(classInfo)) {
345: return Boolean.TRUE;
346: }
347: return Boolean.FALSE;
348: } else if (data instanceof MethodInfo) {
349: MethodInfo methodInfo = (MethodInfo) data;
350: if (node.getDeclaringTypePattern().matchType(
351: methodInfo.getDeclaringType())) {
352: return null;// it might not match further because of modifiers etc
353: }
354: return Boolean.FALSE;
355: }
356: return Boolean.FALSE;
357: }
358:
359: public Object visit(ASTConstructorPattern node, Object data) {
360: if (data instanceof ClassInfo) {
361: ClassInfo classInfo = (ClassInfo) data;
362: if (node.getDeclaringTypePattern().matchType(classInfo)) {
363: // we matched but the actual match result may be false
364: return Boolean.TRUE;
365: }
366: } else if (data instanceof ConstructorInfo) {
367: ConstructorInfo constructorInfo = (ConstructorInfo) data;
368: if (node.getDeclaringTypePattern().matchType(
369: constructorInfo.getDeclaringType())) {
370: return null;// it might not match further because of modifiers etc
371: }
372: return Boolean.FALSE;
373: }
374: return Boolean.FALSE;
375: }
376:
377: public Object visit(ASTFieldPattern node, Object data) {
378: if (data instanceof ClassInfo) {
379: ClassInfo classInfo = (ClassInfo) data;
380: if (node.getDeclaringTypePattern().matchType(classInfo)) {
381: // we matched but the actual match result may be false
382: return Boolean.TRUE;
383: }
384: } else if (data instanceof FieldInfo) {
385: FieldInfo fieldInfo = (FieldInfo) data;
386: if (node.getDeclaringTypePattern().matchType(
387: fieldInfo.getDeclaringType())) {
388: return null;// it might not match further because of modifiers etc
389: }
390: return Boolean.FALSE;
391: }
392: return Boolean.FALSE;
393: }
394:
395: public Object visit(ASTParameter node, Object data) {
396: ClassInfo parameterType = (ClassInfo) data;
397: if (node.getDeclaringClassPattern().matchType(parameterType)) {
398: // we matched but the actual match result may be false
399: return Boolean.TRUE;
400: } else {
401: return Boolean.FALSE;
402: }
403: }
404:
405: public Object visit(ASTArgParameter node, Object data) {
406: // never called
407: return Boolean.TRUE;
408: }
409:
410: public Object visit(ASTAttribute node, Object data) {
411: // called for class level annotation matching f.e. in a within context
412: boolean matchAnnotation = false;
413: AnnotationElement.Annotation[] annotations = (AnnotationElement.Annotation[]) data;
414: for (int i = 0; i < annotations.length; i++) {
415: AnnotationElement.Annotation annotation = annotations[i];
416: if (annotation.getInterfaceName().equals(node.getName())) {
417: matchAnnotation = true;
418: }
419: }
420: if (node.isNot()) {
421: return Util.booleanValueOf(!matchAnnotation);
422: } else {
423: return Util.booleanValueOf(matchAnnotation);
424: }
425: }
426:
427: public Object visit(ASTModifier node, Object data) {
428: // TODO
429: return null;
430: }
431:
432: /**
433: * Returns the string representation of the AST.
434: *
435: * @return
436: */
437: public String toString() {
438: return m_expression;
439: }
440: }
|