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.ASTCall;
11 import org.codehaus.aspectwerkz.expression.ast.ASTCflow;
12 import org.codehaus.aspectwerkz.expression.ast.ASTCflowBelow;
13 import org.codehaus.aspectwerkz.expression.ast.ASTExecution;
14 import org.codehaus.aspectwerkz.expression.ast.ASTGet;
15 import org.codehaus.aspectwerkz.expression.ast.ASTHandler;
16 import org.codehaus.aspectwerkz.expression.ast.ASTNot;
17 import org.codehaus.aspectwerkz.expression.ast.ASTPointcutReference;
18 import org.codehaus.aspectwerkz.expression.ast.ASTRoot;
19 import org.codehaus.aspectwerkz.expression.ast.ASTSet;
20 import org.codehaus.aspectwerkz.expression.ast.ASTStaticInitialization;
21 import org.codehaus.aspectwerkz.expression.ast.ASTWithin;
22 import org.codehaus.aspectwerkz.expression.ast.ASTWithinCode;
23 import org.codehaus.aspectwerkz.expression.ast.ASTArgs;
24 import org.codehaus.aspectwerkz.expression.ast.ASTArgParameter;
25 import org.codehaus.aspectwerkz.expression.ast.ASTHasField;
26 import org.codehaus.aspectwerkz.expression.ast.ASTHasMethod;
27
28 /***
29 * The Cflow expression visitor used at runtime. <p/>This visitor does a parse on a compsosite context, based on the
30 * gathered cflow related context AND the joinpoint context. <p/>This allow to parse complex cflow expression like "(pc1
31 * AND cf1 AND cf3) OR (pc2 AND cf2)".
32 *
33 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
34 * @author Michael Nascimento
35 */
36 public class CflowExpressionVisitorRuntime extends ExpressionVisitor {
37 /***
38 * Creates a new cflow runtime visitor.
39 *
40 * @param expression the expression as a string
41 * @param namespace the namespace
42 * @param root the AST root
43 */
44 public CflowExpressionVisitorRuntime(final ExpressionInfo expressionInfo,
45 final String expression,
46 final String namespace,
47 final ASTRoot root) {
48 super(expressionInfo, expression, namespace, root);
49 }
50
51 /***
52 * Matches the cflow information stack.
53 *
54 * @param contexts the cflow gathered contexts
55 * @param jpContext the joinpoint context
56 * @return true if parse
57 */
58 public boolean matchCflowStack(final Object[] contexts, final ExpressionContext jpContext) {
59 CompositeContext compositeContext = new CompositeContext();
60 ExpressionContext[] ctxs = new ExpressionContext[contexts.length];
61 for (int i = 0; i < ctxs.length; i++) {
62 ctxs[i] = (ExpressionContext) contexts[i];
63 }
64 compositeContext.cflowContexts = ctxs;
65 compositeContext.expressionContext = jpContext;
66 return matchCflowStack(compositeContext);
67 }
68
69 public Object visit(ASTNot node, Object data) {
70 Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
71 if (match.equals(Boolean.TRUE)) {
72 return Boolean.FALSE;
73 } else {
74 return Boolean.TRUE;
75 }
76 }
77
78 public Object visit(ASTPointcutReference node, Object data) {
79 CompositeContext context = (CompositeContext) data;
80 ExpressionNamespace namespace = ExpressionNamespace.getNamespace(m_namespace);
81 CflowExpressionVisitorRuntime expression = namespace.getCflowExpressionRuntime(node.getName());
82 return new Boolean(expression.matchCflowStack(context));
83 }
84
85 public Object visit(ASTExecution node, Object data) {
86 return super.visit(node, ((CompositeContext) data).getLocalContext());
87 }
88
89 public Object visit(ASTCall node, Object data) {
90 return super.visit(node, ((CompositeContext) data).getLocalContext());
91 }
92
93 public Object visit(ASTSet node, Object data) {
94 return super.visit(node, ((CompositeContext) data).getLocalContext());
95 }
96
97 public Object visit(ASTGet node, Object data) {
98 return super.visit(node, ((CompositeContext) data).getLocalContext());
99 }
100
101 public Object visit(ASTHandler node, Object data) {
102 return super.visit(node, ((CompositeContext) data).getLocalContext());
103 }
104
105 public Object visit(ASTWithin node, Object data) {
106 return super.visit(node, ((CompositeContext) data).getLocalContext());
107 }
108
109 public Object visit(ASTWithinCode node, Object data) {
110 return super.visit(node, ((CompositeContext) data).getLocalContext());
111 }
112
113 public Object visit(ASTStaticInitialization node, Object data) {
114 return super.visit(node, ((CompositeContext) data).getLocalContext());
115 }
116
117 public Object visit(ASTArgs node, Object data) {
118 return super.visit(node, ((CompositeContext) data).getLocalContext());
119 }
120
121 public Object visit(ASTHasMethod node, Object data) {
122 return super.visit(node, ((CompositeContext) data).getLocalContext());
123 }
124
125 public Object visit(ASTHasField node, Object data) {
126 return super.visit(node, ((CompositeContext) data).getLocalContext());
127 }
128
129 public Object visit(ASTCflow node, Object data) {
130 CompositeContext compositeContext = (CompositeContext) data;
131 try {
132 for (int i = 0; i < compositeContext.cflowContexts.length; i++) {
133 compositeContext.localContext = compositeContext.cflowContexts[i];
134 Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
135 if (match.booleanValue()) {
136 return Boolean.TRUE;
137 }
138 }
139 return Boolean.FALSE;
140 } finally {
141 compositeContext.localContext = null;
142 }
143 }
144
145 public Object visit(ASTCflowBelow node, Object data) {
146 CompositeContext compositeContext = (CompositeContext) data;
147 try {
148 for (int i = 0; i < compositeContext.cflowContexts.length; i++) {
149 compositeContext.localContext = compositeContext.cflowContexts[i];
150 Boolean match = (Boolean) node.jjtGetChild(0).jjtAccept(this, data);
151 if (match.booleanValue()) {
152 return Boolean.TRUE;
153 }
154 }
155 return Boolean.FALSE;
156 } finally {
157 compositeContext.localContext = null;
158 }
159 }
160
161 /***
162 * Matches the cflow information stack.
163 *
164 * @param compositeContext the composite context
165 * @return true if parse
166 */
167 private boolean matchCflowStack(final CompositeContext compositeContext) {
168 return ((Boolean) visit(m_root, compositeContext)).booleanValue();
169 }
170
171
172
173
174 /***
175 * A composite context for use in cflow evaluation at runtime.
176 *
177 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
178 */
179 static class CompositeContext {
180 public ExpressionContext expressionContext;
181
182 public ExpressionContext[] cflowContexts;
183
184 public ExpressionContext localContext;
185
186 /***
187 * The actual local context is the dependent on where we are in the tree. <p/>Local context is the join point
188 * context - when outside of cflow subtree. - else it is one of the cflow contexts that we iterate over.
189 *
190 * @return the expression
191 */
192 public ExpressionContext getLocalContext() {
193 return (localContext == null) ? expressionContext : localContext;
194 }
195 }
196 }