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.cflow;
    9
    10  import org.codehaus.aspectwerkz.expression.ExpressionInfo;
    11  import org.codehaus.aspectwerkz.definition.SystemDefinition;
    12  import org.codehaus.aspectwerkz.definition.AspectDefinition;
    13  import org.codehaus.aspectwerkz.definition.AdviceDefinition;
    14  import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
    15  import org.codehaus.aspectwerkz.reflect.ClassInfo;
    16  import org.codehaus.aspectwerkz.reflect.MethodInfo;
    17  import org.codehaus.aspectwerkz.aspect.AdviceType;
    18
    19  import java.util.List;
    20  import java.util.ArrayList;
    21
    22  /***
    23   * A Cflow binding represents an extracted cflow or cflowbelow subexpression
    24   * <p/>
    25   * For a given pointcut "pcA and cflowA or cflowbelowB", we will extract two bindings.
    26   * The m_cflowID must be unique on a per cflow sub expresion basis ie JVM wide.
    27   * <p/>
    28   * Note: CflowBinding hashcode depends on Cflow_ID (sub expr) + isCflowBelow only.
    29   *
    30   * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
    31   */
    32  public class CflowBinding {
    33
    34      /***
    35       * the base implementation that hosts the cflow advices
    36       */
    37      private final static ClassInfo ABSTRACT_CFLOWCLASS = JavaClassInfo.getClassInfo(AbstractCflowSystemAspect.class);
    38      private final static MethodInfo CFLOW_ENTER_ADVICE;
    39      private final static MethodInfo CFLOW_EXIT_ADVICE;
    40      static {
    41          MethodInfo enter = null;
    42          MethodInfo exit = null;
    43          for (int i = 0; i < ABSTRACT_CFLOWCLASS.getMethods().length; i++) {
    44              MethodInfo methodInfo = ABSTRACT_CFLOWCLASS.getMethods()[i];
    45              if (methodInfo.getName().equals("enter")) {
    46                  enter = methodInfo;
    47              } else if (methodInfo.getName().equals("exit")) {
    48                  exit = methodInfo;
    49              }
    50          }
    51          if (enter == null || exit == null) {
    52              throw new Error("Could not gather cflow advices from " + AbstractCflowSystemAspect.class);
    53          } else {
    54              CFLOW_ENTER_ADVICE = enter;
    55              CFLOW_EXIT_ADVICE = exit;
    56          }
    57      }
    58
    59      /***
    60       * cflow unique id
    61       */
    62      private int m_cflowID;
    63
    64      /***
    65       * pointcut that represents this cflow sub-expression
    66       */
    67      private ExpressionInfo m_cflowSubExpression;
    68
    69      /***
    70       * pointcut that represents the containing expression
    71       */
    72      private ExpressionInfo m_outerExpression;
    73
    74      /***
    75       * marker if this binding is a cflow below, not used at the moment
    76       */
    77      private boolean m_isCflowBelow;
    78
    79      /***
    80       * Cosntructs a new cflow binding
    81       *
    82       * @param cflowID
    83       * @param cflowSubExpression
    84       * @param isCflowBelow
    85       */
    86      public CflowBinding(int cflowID, ExpressionInfo cflowSubExpression, ExpressionInfo outerExpression, boolean isCflowBelow) {
    87          m_cflowID = cflowID;
    88          m_cflowSubExpression = cflowSubExpression;
    89          m_outerExpression = outerExpression;
    90          m_isCflowBelow = isCflowBelow;
    91      }
    92
    93      /***
    94       * @return the sub expression
    95       */
    96      public ExpressionInfo getExpression() {
    97          return m_cflowSubExpression;
    98      }
    99
    100     /***
    101      * Extract the cflow bindings from any pointcut
    102      * This includes both cflow and cflowbelow
    103      *
    104      * @param expressionInfo the pointcut expression frow where to extract the cflow bindings
    105      * @return a list of CflowBinding, can be empty
    106      */
    107     public static List getCflowBindingsForCflowOf(ExpressionInfo expressionInfo) {
    108         List cflowBindings = new ArrayList();
    109         if (expressionInfo != null) {
    110             expressionInfo.getCflowAspectExpression().populateCflowAspectBindings(cflowBindings);
    111         }
    112         return cflowBindings;
    113     }
    114
    115     /***
    116      * Create an aspect definition for this cflow binding in the given system.
    117      * The cflow jit aspects will gets compiled and loaded
    118      *
    119      * @param systemDefinition
    120      * @param loader
    121      * @return the cflow aspect definition
    122      */
    123     public AspectDefinition getAspectDefinition(SystemDefinition systemDefinition, ClassLoader loader) {
    124         String aspectName = CflowCompiler.getCflowAspectClassName(m_cflowID);
    125
    126         // check if we have already register this aspect
    127         // TODO: it may happen that the aspect gets register somewhere up in the hierarchy ??
    128         // it is optim only
    129
    130         // TODO: how to do this class define lazyly and not pass in a classloader ?
    131         // could be done in the JIT jp clinit when 1+ advice has a cflow binding
    132         Class aspectClass = CflowCompiler.compileCflowAspectAndAttachToClassLoader(loader, m_cflowID);
    133         ClassInfo cflowAspectInfo = JavaClassInfo.getClassInfo(aspectClass);
    134
    135         AspectDefinition aspectDef = new AspectDefinition(
    136                 aspectName.replace('/', '.'),
    137                 cflowAspectInfo,
    138                 systemDefinition
    139         );
    140         aspectDef.addBeforeAdviceDefinition(
    141                 new AdviceDefinition(
    142                         CFLOW_ENTER_ADVICE.getName(),
    143                         AdviceType.BEFORE,
    144                         null,
    145                         aspectName,
    146                         aspectName,
    147                         m_cflowSubExpression,
    148                         CFLOW_ENTER_ADVICE,
    149                         aspectDef
    150                 )
    151         );
    152         aspectDef.addAfterAdviceDefinition(
    153                 new AdviceDefinition(
    154                         CFLOW_EXIT_ADVICE.getName(),
    155                         AdviceType.AFTER_FINALLY,
    156                         null,
    157                         aspectName,
    158                         aspectName,
    159                         m_cflowSubExpression,
    160                         CFLOW_EXIT_ADVICE,
    161                         aspectDef
    162                 )
    163         );
    164
    165         return aspectDef;
    166     }
    167
    168     public boolean isCflowBelow() {
    169         return m_isCflowBelow;
    170     }
    171
    172     public int getCflowID() {
    173         return m_cflowID;
    174     }
    175
    176     public boolean equals(Object o) {
    177         if (this == o) return true;
    178         if (!(o instanceof CflowBinding)) return false;
    179
    180         final CflowBinding cflowBinding = (CflowBinding) o;
    181
    182         if (m_cflowID != cflowBinding.m_cflowID) return false;
    183         if (m_isCflowBelow != cflowBinding.m_isCflowBelow) return false;
    184
    185         return true;
    186     }
    187
    188     public int hashCode() {
    189         int result;
    190         result = m_cflowID;
    191         result = 29 * result + (m_isCflowBelow ? 1 : 0);
    192         return result;
    193     }
    194 }