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 }