View Javadoc

    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.expression.ExpressionNamespace;
    12  import org.codehaus.aspectwerkz.expression.regexp.Pattern;
    13  import org.codehaus.aspectwerkz.util.Strings;
    14  import org.codehaus.aspectwerkz.aspect.AdviceType;
    15  import org.codehaus.aspectwerkz.DeploymentModel;
    16  import org.codehaus.aspectwerkz.reflect.MethodInfo;
    17  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    18  import org.codehaus.aspectwerkz.exception.DefinitionException;
    19
    20  import java.util.Iterator;
    21  import java.util.Collection;
    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 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 name,
    40                                                            final String 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 pointcutName = name;
    50          String 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[] parameters = Strings.splitString(pointcutCallSignature, ",");
    66                  for (int i = 0; i < parameters.length; i++) {
    67                      String[] 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 name,
    86                                                        final String 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 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 newExpression;
    106         if (oldExpressionInfo != null) {
    107             String 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 newExpression = new StringBuffer();
    133         final ExpressionInfo oldExpressionInfo = virtualAdviceDef.getExpressionInfo();
    134         if (oldExpressionInfo != null) {
    135             String oldExpression = oldExpressionInfo.toString();
    136             newExpression.append(oldExpression);
    137         }
    138         final Collection deploymentScopes = systemDef.getDeploymentScopes();
    139         if (deploymentScopes.size() != 0 && oldExpressionInfo != null) {
    140             newExpression.append(" || ");
    141         }
    142         for (Iterator 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 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 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 expression,
    207                                                                        final String introductionName,
    208                                                                        final String 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 adviceName,
    234                                                           final AdviceType adviceType,
    235                                                           final String expression,
    236                                                           final String specialArgumentType,
    237                                                           final String aspectName,
    238                                                           final String 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 adviceCallSignature = null;
    248         String resolvedSpecialArgumentType = specialArgumentType;
    249         if (adviceName.indexOf('(') > 0) {
    250             adviceCallSignature = adviceName.substring(adviceName.indexOf('(') + 1, adviceName.lastIndexOf(')'));
    251             String[] parameters = Strings.splitString(adviceCallSignature, ",");
    252             for (int i = 0; i < parameters.length; i++) {
    253                 String[] 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 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) 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 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 introductionName,
    339                                                                                         final String expression,
    340                                                                                         final String 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 }