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.definition;
9
10 import org.codehaus.aspectwerkz.expression.ExpressionInfo;
11 import org.codehaus.aspectwerkz.aspect.AdviceType;
12 import org.codehaus.aspectwerkz.reflect.MethodInfo;
13 import org.codehaus.aspectwerkz.util.Strings;
14 import org.codehaus.aspectwerkz.DeploymentModel;
15 import org.codehaus.aspectwerkz.cflow.CflowBinding;
16
17 import java.util.List;
18
19 /***
20 * Holds the meta-data for the advices.
21 *
22 * @author <a href="mailto:jboner@codehaus.org">Jonas Boner </a>
23 */
24 public class AdviceDefinition {
25
26 /***
27 * The name of the advice.
28 * It is the advice method name and optionnaly the call signature.
29 * e.g. advice or advice() or advice(JoinPoint jp) or myadvice(JoinPoint myJp , java.lang.String foo) ...
30 */
31 private String m_name;
32
33 /***
34 * The type of the advice.
35 */
36 private AdviceType m_type;
37
38 /***
39 * The aspect class name.
40 */
41 private final String m_aspectClassName;
42
43 /***
44 * The aspect name.
45 */
46 private final String m_aspectName;
47
48 /***
49 * The pointcut expression.
50 */
51 private ExpressionInfo m_expressionInfo;
52
53 /***
54 * The method for the advice.
55 */
56 private final MethodInfo m_method;
57
58 /***
59 * The attribute for the advice.
60 */
61 private String m_attribute = "";
62
63 /***
64 * The aspect definition holding this advice definition.
65 */
66 private AspectDefinition m_aspectDefinition;
67
68 /***
69 * The special arg type, such as returning(TYPE) or throwing(TYPE).
70 */
71 private String m_specialArgumentType;
72
73 /***
74 * Indicates if this advice will need a cflow or cflowbelow runtime check
75 */
76 private boolean m_hasCflowOrCflowBelow = false;
77
78 /***
79 * TODO only use this method and make ctor private?
80 * <p/>
81 * Creates a new advice definition.
82 *
83 * @param adviceName the advice name
84 * @param adviceType the advice type
85 * @param expression the advice expression
86 * @param specialArgumentType the arg
87 * @param aspectName the aspect name
88 * @param aspectClassName the aspect class name
89 * @param method the advice method
90 * @param aspectDef the aspect definition
91 * @return the new advice definition
92 */
93 public static AdviceDefinition newInstance(final String adviceName,
94 final AdviceType adviceType,
95 final String expression,
96 final String specialArgumentType,
97 final String aspectName,
98 final String aspectClassName,
99 final MethodInfo method,
100 final AspectDefinition aspectDef) {
101 ExpressionInfo expressionInfo = new ExpressionInfo(
102 expression,
103 aspectDef.getQualifiedName()
104 );
105
106
107 String adviceCallSignature = null;
108 String resolvedSpecialArgumentType = specialArgumentType;
109 if (adviceName.indexOf('(') > 0) {
110 adviceCallSignature = adviceName.substring(adviceName.indexOf('(') + 1, adviceName.lastIndexOf(')'));
111 String[] parameters = Strings.splitString(adviceCallSignature, ",");
112 for (int i = 0; i < parameters.length; i++) {
113 String[] parameterInfo = Strings.splitString(
114 Strings.replaceSubString(parameters[i].trim(), " ", " "),
115 " "
116 );
117
118 if (parameterInfo[1].equals(specialArgumentType)) {
119 resolvedSpecialArgumentType = parameterInfo[0];
120 expressionInfo.setSpecialArgumentName(parameterInfo[1]);
121 } else {
122 expressionInfo.addArgument(
123 parameterInfo[1],
124 parameterInfo[0],
125 aspectDef.getClassInfo().getClassLoader()
126 );
127 }
128 }
129 }
130
131 return new AdviceDefinition(
132 adviceName,
133 adviceType,
134 resolvedSpecialArgumentType,
135 aspectName,
136 aspectClassName,
137 expressionInfo,
138 method,
139 aspectDef
140 );
141 }
142
143 /***
144 * Creates a new advice meta-data instance.
145 *
146 * @param name the name of the expressionInfo
147 * @param type the type of the advice
148 * @param specialArgumentType the special arg type, such as returning(TYPE) or throwing(TYPE)
149 * @param aspectName the name of the aspect
150 * @param aspectClassName the class name of the aspect
151 * @param expressionInfo the expressionInfo
152 * @param methodInfo the methodInfo
153 */
154 public AdviceDefinition(final String name,
155 final AdviceType type,
156 final String specialArgumentType,
157 final String aspectName,
158 final String aspectClassName,
159 final ExpressionInfo expressionInfo,
160 final MethodInfo methodInfo,
161 final AspectDefinition aspectDef) {
162 if (name == null) {
163 throw new IllegalArgumentException("name can not be null");
164 }
165 if (type == null) {
166 throw new IllegalArgumentException("illegal advice type");
167 }
168 if (aspectName == null) {
169 throw new IllegalArgumentException("aspect name can not be null");
170 }
171 if (aspectClassName == null) {
172 throw new IllegalArgumentException("class name can not be null");
173 }
174 if (methodInfo == null) {
175 throw new IllegalArgumentException("methodInfo can not be null");
176 }
177 if (aspectDef == null) {
178 throw new IllegalArgumentException("aspect definition can not be null");
179 }
180 m_name = name;
181 m_type = type;
182 m_specialArgumentType = specialArgumentType;
183 m_aspectName = aspectName;
184 m_aspectClassName = aspectClassName;
185 m_expressionInfo = expressionInfo;
186 m_method = methodInfo;
187 m_aspectDefinition = aspectDef;
188
189
190 List cflowBindings = CflowBinding.getCflowBindingsForCflowOf(m_expressionInfo);
191 m_hasCflowOrCflowBelow = (cflowBindings.size() > 0);
192 }
193
194 /***
195 * Returns the advice type.
196 *
197 * @return the advice type
198 */
199 public AdviceType getType() {
200 return m_type;
201 }
202
203 /***
204 * Returns the name of the advice.
205 *
206 * @return the name
207 */
208 public String getName() {
209 return m_name;
210 }
211
212 /***
213 * Returns the fully qualified name for the advice
214 *
215 * @return the fully qualified name
216 */
217 public String getQualifiedName() {
218 return m_aspectDefinition.getQualifiedName() + '.' + m_name;
219 }
220
221 /***
222 * Sets the name of the advice.
223 *
224 * @param name the name
225 */
226 public void setName(final String name) {
227 m_name = name.trim();
228 }
229
230 /***
231 * Returns the expression.
232 * <p/>
233 * TODO should return NULL object if null
234 *
235 * @return the expression
236 */
237 public ExpressionInfo getExpressionInfo() {
238 return m_expressionInfo;
239 }
240
241 /***
242 * Sets the expression info.
243 *
244 * @param newExpression the new expression info
245 */
246 public void setExpressionInfo(final ExpressionInfo newExpression) {
247 m_expressionInfo = newExpression;
248
249 List cflowBindings = CflowBinding.getCflowBindingsForCflowOf(m_expressionInfo);
250 m_hasCflowOrCflowBelow = (cflowBindings.size() > 0);
251 }
252
253 /***
254 * Returns the class name.
255 *
256 * @return the class name
257 */
258 public String getAspectClassName() {
259 return m_aspectClassName;
260 }
261
262 /***
263 * Returns the aspect name.
264 *
265 * @return the aspect name
266 */
267 public String getAspectName() {
268 return m_aspectName;
269 }
270
271 /***
272 * Returns the special arg type, such as returning(TYPE) or throwing(TYPE).
273 *
274 * @return
275 */
276 public String getSpecialArgumentType() {
277 return m_specialArgumentType;
278 }
279
280 /***
281 * Returns the method.
282 *
283 * @return the method
284 */
285 public MethodInfo getMethodInfo() {
286 return m_method;
287 }
288
289 /***
290 * Returns the the deployment model for the advice
291 *
292 * @return the deployment model
293 */
294 public DeploymentModel getDeploymentModel() {
295 return m_aspectDefinition.getDeploymentModel();
296 }
297
298 /***
299 * Returns the attribute.
300 *
301 * @return the attribute
302 */
303 public String getAttribute() {
304 return m_attribute;
305 }
306
307 /***
308 * Sets the attribute.
309 *
310 * @param attribute the attribute
311 */
312 public void setAttribute(final String attribute) {
313 m_attribute = attribute;
314 }
315
316 /***
317 * Returns the definition for the aspect that defines this advice.
318 *
319 * @return the aspect definition
320 */
321 public AspectDefinition getAspectDefinition() {
322 return m_aspectDefinition;
323 }
324
325 /***
326 * Check if the advice is bound to a pointcut with cflow or cflowbelow
327 *
328 * @return
329 */
330 public boolean hasCflowOrCflowBelow() {
331 return m_hasCflowOrCflowBelow;
332 }
333
334 /***
335 * Deep copy of the definition.
336 *
337 * @param expressionInfo
338 * @return
339 */
340 public AdviceDefinition copyAt(final ExpressionInfo expressionInfo) {
341 return new AdviceDefinition(
342 getName(),
343 getType(),
344 getSpecialArgumentType(),
345 getAspectName(),
346 getAspectClassName(),
347 expressionInfo,
348 getMethodInfo(),
349 m_aspectDefinition
350 );
351 }
352
353 /***
354 * Equals and hashcode means we have the same advice if the aspect qualified name (not classname) and
355 * advice name (may include signature) are the same. [AW-439 fix]
356 *
357 * @param o
358 * @return
359 */
360 public boolean equals(Object o) {
361 if (this == o) return true;
362 if (!(o instanceof AdviceDefinition)) return false;
363
364 final AdviceDefinition adviceDefinition = (AdviceDefinition) o;
365
366 if (!m_aspectName.equals(adviceDefinition.m_aspectName)) return false;
367 if (!m_name.equals(adviceDefinition.m_name)) return false;
368
369 return true;
370 }
371
372 public int hashCode() {
373 int result;
374 result = m_name.hashCode();
375 result = 29 * result + m_aspectName.hashCode();
376 return result;
377 }
378 }