KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > definition > DefinitionParserHelper


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.definition;
5
6
7 import com.tc.aspectwerkz.DeploymentModel;
8 import com.tc.aspectwerkz.reflect.ClassInfo;
9 import com.tc.aspectwerkz.reflect.MethodInfo;
10 import com.tc.aspectwerkz.reflect.ClassInfoHelper;
11 import com.tc.aspectwerkz.aspect.AdviceType;
12 import com.tc.aspectwerkz.exception.DefinitionException;
13 import com.tc.aspectwerkz.expression.regexp.Pattern;
14 import com.tc.aspectwerkz.expression.ExpressionInfo;
15 import com.tc.aspectwerkz.expression.ExpressionNamespace;
16 import com.tc.aspectwerkz.transform.TransformationConstants;
17 import com.tc.aspectwerkz.util.Strings;
18
19 import java.util.Iterator JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.List JavaDoc;
22
23 /**
24  * Helper class for the attribute and the XML definition parsers.
25  *
26  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
27  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
28  */

29 public class DefinitionParserHelper {
30   public static final String JavaDoc EXPRESSION_PREFIX = "AW_";
31
32   /**
33    * Creates and adds pointcut definition to aspect definition.
34    *
35    * @param name
36    * @param expression
37    * @param aspectDef
38    */

39   public static void createAndAddPointcutDefToAspectDef(final String JavaDoc name,
40                                                         final String JavaDoc expression,
41                                                         final AspectDefinition aspectDef) {
42     PointcutDefinition pointcutDef = new PointcutDefinition(expression);
43     aspectDef.addPointcutDefinition(pointcutDef);
44
45     // name can be the "pcName(paramType paramName)"
46
// extract the parameter name to type map
47
// and register the pointcut using its name
48
//TODO: support for same pc name and different signature
49
String JavaDoc pointcutName = name;
50     String JavaDoc pointcutCallSignature = null;
51     if (name.indexOf("(") > 0) {
52       pointcutName = name.substring(0, name.indexOf("("));
53       pointcutCallSignature = name.substring(name.indexOf("(") + 1, name.lastIndexOf(")"));
54     }
55
56     // do a lookup first to avoid infinite recursion when:
57
// <pointcut name="pc" ...> [will be registered as pc]
58
// <advice bind-to="pc" ...> [will be registered as pc and should not override previous one !]
59
ExpressionNamespace namespace = ExpressionNamespace.getNamespace(aspectDef.getQualifiedName());
60     ExpressionInfo info = namespace.getExpressionInfoOrNull(pointcutName);
61     if (info == null) {
62       info = new ExpressionInfo(expression, aspectDef.getQualifiedName());
63       // extract the pointcut signature map
64
if (pointcutCallSignature != null) {
65         String JavaDoc[] parameters = Strings.splitString(pointcutCallSignature, ",");
66         for (int i = 0; i < parameters.length; i++) {
67           String JavaDoc[] parameterInfo = Strings.splitString(
68                   Strings.replaceSubString(parameters[i].trim(), " ", " "),
69                   " "
70           );
71           info.addArgument(parameterInfo[1], parameterInfo[0], aspectDef.getClassInfo().getClassLoader());
72         }
73       }
74     }
75     ExpressionNamespace.getNamespace(aspectDef.getQualifiedName()).addExpressionInfo(pointcutName, info);
76   }
77
78   /**
79    * Creates and adds a prepared pointcut definition to virtual aspect definition.
80    *
81    * @param name
82    * @param expression
83    * @param systemDef
84    */

85   public static void createAndAddDeploymentScopeDef(final String JavaDoc name,//TODO Depl scpope(prasen)field name not unique - need FQN
86
final String JavaDoc expression,
87                                                     final SystemDefinition systemDef) {
88     AspectDefinition aspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
89     aspectDef.addPointcutDefinition(new PointcutDefinition(expression));
90     systemDef.addDeploymentScope(new DeploymentScope(name, expression));
91   }
92
93   /**
94    * Creates and adds an advisable definition to virtual aspect definition.
95    *
96    * @param expression
97    * @param systemDef
98    */

99   public static void createAndAddAdvisableDef(final String JavaDoc expression, final SystemDefinition systemDef) {
100     AspectDefinition virtualAspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
101     virtualAspectDef.addPointcutDefinition(new PointcutDefinition(expression));
102
103     AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef.getBeforeAdviceDefinitions().get(0);
104     ExpressionInfo oldExpressionInfo = virtualAdviceDef.getExpressionInfo();
105     String JavaDoc newExpression;
106     if (oldExpressionInfo != null) {
107       String JavaDoc oldExpression = oldExpressionInfo.toString();
108       newExpression = oldExpression + " || " + expression;
109     } else {
110       newExpression = expression;
111     }
112
113     virtualAdviceDef.setExpressionInfo(
114             new ExpressionInfo(
115                     newExpression,
116                     virtualAspectDef.getQualifiedName()
117             )
118     );
119   }
120
121   /**
122    * Attaches all deployment scopes in a system to the virtual advice.
123    *
124    * @param systemDef the system definition
125    */

126   public static void attachDeploymentScopeDefsToVirtualAdvice(final SystemDefinition systemDef) {
127     final AspectDefinition virtualAspectDef = systemDef.getAspectDefinition(Virtual.class.getName());
128     final AdviceDefinition virtualAdviceDef = (AdviceDefinition) virtualAspectDef.getBeforeAdviceDefinitions().get(
129             0
130     );
131
132     final StringBuffer JavaDoc newExpression = new StringBuffer JavaDoc();
133     final ExpressionInfo oldExpressionInfo = virtualAdviceDef.getExpressionInfo();
134     if (oldExpressionInfo != null) {
135       String JavaDoc oldExpression = oldExpressionInfo.toString();
136       newExpression.append(oldExpression);
137     }
138     final Collection JavaDoc deploymentScopes = systemDef.getDeploymentScopes();
139     if (deploymentScopes.size() != 0 && oldExpressionInfo != null) {
140       newExpression.append(" || ");
141     }
142     for (Iterator JavaDoc it = deploymentScopes.iterator(); it.hasNext();) {
143       DeploymentScope deploymentScope = (DeploymentScope) it.next();
144       newExpression.append(deploymentScope.getExpression());
145       if (it.hasNext()) {
146         newExpression.append(" || ");
147       }
148     }
149     if (newExpression.length() != 0) {
150       virtualAdviceDef.setExpressionInfo(
151               new ExpressionInfo(
152                       newExpression.toString(),
153                       virtualAspectDef.getQualifiedName()
154               )
155       );
156     }
157   }
158
159   /**
160    * Creates and add mixin definition to system definition.
161    *
162    * @param mixinClassInfo
163    * @param expression
164    * @param deploymentModel
165    * @param isTransient
166    * @param systemDef
167    * @return the mixin definition
168    */

169   public static MixinDefinition createAndAddMixinDefToSystemDef(final ClassInfo mixinClassInfo,
170                                                                 final String JavaDoc expression,
171                                                                 final DeploymentModel deploymentModel,
172                                                                 final boolean isTransient,
173                                                                 final SystemDefinition systemDef) {
174     final MixinDefinition mixinDef = createMixinDefinition(
175             mixinClassInfo,
176             expression,
177             deploymentModel,
178             isTransient,
179             systemDef
180     );
181
182     // check doublons - TODO change ArrayList to HashMap since NAME is a key
183
MixinDefinition doublon = null;
184     for (Iterator JavaDoc intros = systemDef.getMixinDefinitions().iterator(); intros.hasNext();) {
185       MixinDefinition intro = (MixinDefinition) intros.next();
186       if (intro.getMixinImpl().getName().equals(mixinDef.getMixinImpl().getName())) {
187         doublon = intro;
188         intro.addExpressionInfos(mixinDef.getExpressionInfos());
189         break;
190       }
191     }
192     if (doublon == null) {
193       systemDef.addMixinDefinition(mixinDef);
194     }
195     return mixinDef;
196   }
197
198   /**
199    * Creates and add interface introduction definition to aspect definition.
200    *
201    * @param expression
202    * @param introductionName
203    * @param interfaceClassName
204    * @param aspectDef
205    */

206   public static void createAndAddInterfaceIntroductionDefToAspectDef(final String JavaDoc expression,
207                                                                      final String JavaDoc introductionName,
208                                                                      final String JavaDoc interfaceClassName,
209                                                                      final AspectDefinition aspectDef) {
210     // Introduction name is unique within an aspectDef only
211
InterfaceIntroductionDefinition introDef = createInterfaceIntroductionDefinition(
212             introductionName,
213             expression,
214             interfaceClassName,
215             aspectDef
216     );
217     aspectDef.addInterfaceIntroductionDefinition(introDef);
218   }
219
220   /**
221    * Creates a new advice definition.
222    *
223    * @param adviceName the advice name
224    * @param adviceType the advice type
225    * @param expression the advice expression
226    * @param specialArgumentType the arg
227    * @param aspectName the aspect name
228    * @param aspectClassName the aspect class name
229    * @param methodInfo the advice methodInfo
230    * @param aspectDef the aspect definition
231    * @return the new advice definition
232    */

233   public static AdviceDefinition createAdviceDefinition(final String JavaDoc adviceName,
234                                                         final AdviceType adviceType,
235                                                         final String JavaDoc expression,
236                                                         final String JavaDoc specialArgumentType,
237                                                         final String JavaDoc aspectName,
238                                                         final String JavaDoc aspectClassName,
239                                                         final MethodInfo methodInfo,
240                                                         final AspectDefinition aspectDef) {
241     ExpressionInfo expressionInfo = new ExpressionInfo(
242             expression,
243             aspectDef.getQualifiedName()
244     );
245
246     // support for pointcut signature
247
String JavaDoc adviceCallSignature = null;
248     String JavaDoc resolvedSpecialArgumentType = specialArgumentType;
249     if (adviceName.indexOf('(') > 0) {
250       adviceCallSignature = adviceName.substring(adviceName.indexOf('(') + 1, adviceName.lastIndexOf(')'));
251       String JavaDoc[] parameters = Strings.splitString(adviceCallSignature, ",");
252       for (int i = 0; i < parameters.length; i++) {
253         String JavaDoc[] parameterInfo = Strings.splitString(
254                 Strings.replaceSubString(parameters[i].trim(), " ", " "),
255                 " "
256         );
257         // Note: for XML defined aspect, we support anonymous parameters like
258
// advice(JoinPoint, Rtti) as well as abbreviations, so we have to assign
259
// them a name here, as well as their real type
260
String JavaDoc paramName, paramType = null;
261         if (parameterInfo.length == 2) {
262           paramName = parameterInfo[1];
263           paramType = parameterInfo[0];
264         } else {
265           paramName = "anonymous_" + i;
266           paramType = (String JavaDoc) Pattern.ABBREVIATIONS.get(parameterInfo[0]);
267         }
268         // skip the parameter if this ones is a after returning / throwing binding
269
if (paramName.equals(specialArgumentType)) {
270           resolvedSpecialArgumentType = paramType;
271           expressionInfo.setSpecialArgumentName(paramName);
272         } else {
273           expressionInfo.addArgument(paramName, paramType, aspectDef.getClassInfo().getClassLoader());
274         }
275       }
276     }
277
278     // check that around advice return Object else the compiler will fail
279
if (adviceType.equals(AdviceType.AROUND)) {
280       if (!"java.lang.Object".equals(methodInfo.getReturnType().getName())) {
281         throw new DefinitionException(
282                 "around advice must return java.lang.Object : " + aspectClassName + "." + methodInfo.getName()
283         );
284       }
285     }
286
287     final AdviceDefinition adviceDef = new AdviceDefinition(
288             adviceName,
289             adviceType,
290             resolvedSpecialArgumentType,
291             aspectName,
292             aspectClassName,
293             expressionInfo,
294             methodInfo,
295             aspectDef
296     );
297     return adviceDef;
298   }
299
300   /**
301    * Creates an introduction definition.
302    *
303    * @param mixinClassInfo
304    * @param expression
305    * @param deploymentModel
306    * @param isTransient
307    * @param systemDef
308    * @return
309    */

310   public static MixinDefinition createMixinDefinition(final ClassInfo mixinClassInfo,
311                                                       final String JavaDoc expression,
312                                                       final DeploymentModel deploymentModel,
313                                                       final boolean isTransient,
314                                                       final SystemDefinition systemDef) {
315     final MixinDefinition mixinDef = new MixinDefinition(mixinClassInfo, deploymentModel, isTransient, systemDef);
316     if (expression != null) {
317       ExpressionInfo expressionInfo = new ExpressionInfo(expression, systemDef.getUuid());
318
319       // auto-name the pointcut which is anonymous for introduction
320
ExpressionNamespace.getNamespace(systemDef.getUuid()).addExpressionInfo(
321               EXPRESSION_PREFIX + expression.hashCode(),
322               expressionInfo
323       );
324       mixinDef.addExpressionInfo(expressionInfo);
325     }
326     return mixinDef;
327   }
328
329   /**
330    * Creates a new interface introduction definition.
331    *
332    * @param introductionName the introduction name
333    * @param expression the pointcut expression
334    * @param interfaceClassName the class name of the interface
335    * @param aspectDef the aspect definition
336    * @return the new introduction definition
337    */

338   public static InterfaceIntroductionDefinition createInterfaceIntroductionDefinition(final String JavaDoc introductionName,
339                                                                                       final String JavaDoc expression,
340                                                                                       final String JavaDoc interfaceClassName,
341                                                                                       final AspectDefinition aspectDef) {
342     final InterfaceIntroductionDefinition introDef = new InterfaceIntroductionDefinition(
343             introductionName, interfaceClassName
344     );
345     if (expression != null) {
346       ExpressionInfo expressionInfo = new ExpressionInfo(expression, aspectDef.getQualifiedName());
347
348       // auto-name the pointcut which is anonymous for introduction
349
ExpressionNamespace.getNamespace(aspectDef.getQualifiedName()).addExpressionInfo(
350               EXPRESSION_PREFIX + expression.hashCode(),
351               expressionInfo
352       );
353       introDef.addExpressionInfo(expressionInfo);
354     }
355     return introDef;
356   }
357
358   /**
359    * Creates the advice definitions and adds them to the aspect definition.
360    *
361    * @param type the type of advice
362    * @param bindTo the pointcut expresion
363    * @param name the name of the advice
364    * @param method the method implementing the advice
365    * @param aspectDef the aspect definition
366    */

367   public static void createAndAddAdviceDefsToAspectDef(final String JavaDoc type,
368                                                        final String JavaDoc bindTo,
369                                                        final String JavaDoc name,
370                                                        final MethodInfo method,
371                                                        final AspectDefinition aspectDef) {
372     try {
373       if (type.equalsIgnoreCase("around")) {
374         final String JavaDoc aspectName = aspectDef.getName();
375         AdviceDefinition adviceDef = createAdviceDefinition(
376                 name,
377                 AdviceType.AROUND,
378                 bindTo,
379                 null,
380                 aspectName,
381                 aspectDef.getClassName(),
382                 method,
383                 aspectDef
384         );
385         aspectDef.addAroundAdviceDefinition(adviceDef);
386
387       } else if (type.equalsIgnoreCase("before")) {
388         final String JavaDoc aspectName = aspectDef.getName();
389         AdviceDefinition adviceDef = createAdviceDefinition(
390                 name,
391                 AdviceType.BEFORE,
392                 bindTo,
393                 null,
394                 aspectName,
395                 aspectDef.getClassName(),
396                 method,
397                 aspectDef
398         );
399         aspectDef.addBeforeAdviceDefinition(adviceDef);
400
401       } else if (type.startsWith("after")) {
402         String JavaDoc specialArgumentType = null;
403         AdviceType adviceType = AdviceType.AFTER;
404         if (type.startsWith("after returning(")) {
405           adviceType = AdviceType.AFTER_RETURNING;
406           int start = type.indexOf('(');
407           int end = type.indexOf(')');
408           specialArgumentType = type.substring(start + 1, end).trim();
409         } else if (type.startsWith("after throwing(")) {
410           adviceType = AdviceType.AFTER_THROWING;
411           int start = type.indexOf('(');
412           int end = type.indexOf(')');
413           specialArgumentType = type.substring(start + 1, end).trim();
414         } else if (type.startsWith("after returning")) {
415           adviceType = AdviceType.AFTER_RETURNING;
416         } else if (type.startsWith("after throwing")) {
417           adviceType = AdviceType.AFTER_THROWING;
418         } else if (type.startsWith("after")) {
419           adviceType = AdviceType.AFTER_FINALLY;
420         } else if (type.startsWith("after finally")) {
421           adviceType = AdviceType.AFTER_FINALLY;
422         }
423         if (specialArgumentType != null && specialArgumentType.indexOf(' ') > 0) {
424           throw new DefinitionException(
425                   "argument to after (returning/throwing) can only be a type (parameter name binding should be done using args(..))"
426           );
427         }
428         final String JavaDoc aspectName = aspectDef.getName();
429         AdviceDefinition adviceDef = createAdviceDefinition(
430                 name,
431                 adviceType,
432                 bindTo,
433                 specialArgumentType,
434                 aspectName,
435                 aspectDef.getClassName(),
436                 method,
437                 aspectDef
438         );
439
440         aspectDef.addAfterAdviceDefinition(adviceDef);
441       } else {
442         throw new DefinitionException("Unkonw type for advice : " + type);
443       }
444     } catch (DefinitionException e) {
445       System.err.println(
446               "WARNING: unable to register advice " + aspectDef.getName() + "." + name +
447                       " at pointcut [" + bindTo + "] due to: " + e.getMessage()
448       );
449       // TODO ALEX - better handling of reg issue (f.e. skip the whole aspect, in DocumentParser, based on DefinitionE
450
}
451   }
452
453   public static MethodInfo createMethodInfoForAdviceFQN(final String JavaDoc name,
454                                                         final AspectDefinition aspectDef,
455                                                         final ClassInfo aspectClassInfo) {
456     List JavaDoc adviceMethodList = ClassInfoHelper.createMethodList(aspectClassInfo);
457     MethodInfo method = null;
458     for (Iterator JavaDoc it3 = adviceMethodList.iterator(); it3.hasNext();) {
459       MethodInfo methodCurrent = (MethodInfo) it3.next();
460       if (aspectDef.isAspectWerkzAspect()) {
461         if (matchMethodAsAdvice(methodCurrent, name)) {
462           method = methodCurrent;
463           break;
464         }
465       } else {
466         // TODO support matchMethodAsAdvice(..) for all aspect models? if so use stuff below
467
// AspectModel aspectModel = AspectModelManager.getModelFor(aspectDef.getAspectModel());
468
// if (aspectModel.matchMethodAsAdvice(methodCurrent, name)) {
469
// method = methodCurrent;
470
// break;
471
// }
472
if (methodCurrent.getName().equals(name)) {
473           method = methodCurrent;
474           break;
475         }
476       }
477     }
478     if (method == null) {
479       throw new DefinitionException(
480               "could not find advice method [" + name + "] in [" + aspectClassInfo.getName() +
481                       "] (are you using a compiler extension that you have not registered?)" +
482                       " (are you using XML defined advice, with StaticJoinPoint bindings without specifying the full" +
483                       "source like signature?)"
484       );
485     }
486     return method;
487   }
488
489   /**
490    * Check if a method from an aspect class match a given advice signature.
491    * <br/>
492    * If the signature is just a method name, then we have a match even if JoinPoint is sole method parameter.
493    * Else we match both method name and parameters type, with abbreviation support (java.lang.* and JoinPoint)
494    *
495    * @param method
496    * @param adviceSignature
497    * @return boolean
498    */

499   private static boolean matchMethodAsAdvice(MethodInfo method, String JavaDoc adviceSignature) {
500     // grab components from adviceSignature
501
//TODO catch AOOBE for better syntax error reporting
502
String JavaDoc[] signatureElements = Strings.extractMethodSignature(adviceSignature);
503
504     // check method name
505
if (!method.getName().equals(signatureElements[0])) {
506       return false;
507     }
508     // check number of args
509
if (method.getParameterTypes().length * 2 != signatureElements.length - 1) {
510       // we still match if method has "JoinPoint" has sole parameter
511
// and adviceSignature has none
512
if (signatureElements.length == 1 &&
513               method.getParameterTypes().length == 1 &&
514               (method.getParameterTypes()[0].getName().equals(TransformationConstants.JOIN_POINT_JAVA_CLASS_NAME)
515                       || method.getParameterTypes()[0].getName().equals(TransformationConstants.STATIC_JOIN_POINT_JAVA_CLASS_NAME)))
516       {
517         return true;
518       } else {
519         return false;
520       }
521     }
522     int argIndex = 0;
523     for (int i = 1; i < signatureElements.length; i++) {
524       String JavaDoc paramType = signatureElements[i++];
525       String JavaDoc methodParamType = method.getParameterTypes()[argIndex++].getName();
526       // handle shortcuts for java.lang.* and JoinPoint, StaticJoinPoint and Rtti
527
String JavaDoc paramTypeResolved = (String JavaDoc) Pattern.ABBREVIATIONS.get(paramType);
528       if (methodParamType.equals(paramType) || methodParamType.equals(paramTypeResolved)) {
529         continue;
530       } else {
531         return false;
532       }
533     }
534     return true;
535   }
536 }
Popular Tags