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.reflect.ClassInfo;
12  import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
13  import org.codehaus.aspectwerkz.reflect.MethodInfo;
14  import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
15  import org.codehaus.aspectwerkz.DeploymentModel;
16  import org.codehaus.aspectwerkz.aspect.DefaultMixinFactory;
17  import org.codehaus.aspectwerkz.intercept.AdvisableImpl;
18  import org.codehaus.aspectwerkz.intercept.Advisable;
19  import org.codehaus.aspectwerkz.transform.TransformationConstants;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.HashMap;
26  import java.lang.ref.WeakReference;
27  
28  /***
29   * Definition for the mixin construct.
30   *
31   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
32   */
33  public class MixinDefinition {
34  
35      private final static String DEFAULT_MIXIN_FACTORY = DefaultMixinFactory.class.getName().replace('/', '.');
36      /***
37       * The deployment model for the mixin.
38       */
39      private DeploymentModel m_deploymentModel;
40  
41      /***
42       * Flags the mixin as transient.
43       */
44      private boolean m_isTransient;
45  
46      /***
47       * The introduced methods info list.
48       */
49      private final List m_methodsToIntroduce = new ArrayList();
50  
51      /***
52       * The interface classes name.
53       */
54      private final List m_interfaceClassNames = new ArrayList();
55  
56      /***
57       * The class name for the mixin impl.
58       */
59      private final String m_mixinImplClassName;
60  
61      /***
62       * The class loader.
63       */
64      private final WeakReference m_loaderRef;
65  
66      /***
67       * The mixin expressions.
68       */
69      private ExpressionInfo[] m_expressionInfos = new ExpressionInfo[]{};
70  
71      /***
72       * The attribute for the mixin.
73       */
74      private String m_attribute = "";
75  
76      /***
77       * The factory class name.
78       */
79      private String m_factoryClassName;
80  
81      /***
82       * The system definition.
83       */
84      private SystemDefinition m_systemDefinition;
85  
86      /***
87       * The parameters passed to the mixin at definition time.
88       */
89      private Map m_parameters = new HashMap();
90  
91      /***
92       * Construct a new definition for mixin.
93       *
94       * @param mixinClass      the mixin class
95       * @param deploymentModel mixin deployment model
96       * @param isTransient     transient flag
97       * @param systemDef       the system definition
98       */
99      public MixinDefinition(ClassInfo mixinClass,
100                            final DeploymentModel deploymentModel,
101                            final boolean isTransient,
102                            final SystemDefinition systemDef) {
103         if (isSystemMixin(mixinClass)) {
104             mixinClass = defineSystemMixin(mixinClass.getClassLoader());
105         } else {
106             List allInterfaces = ClassInfoHelper.collectInterfaces(mixinClass);
107             for (Iterator iterator = allInterfaces.iterator(); iterator.hasNext();) {
108                 ClassInfo interfaceInfo = (ClassInfo) iterator.next();
109                 m_interfaceClassNames.add(interfaceInfo.getName());
110             }
111 
112             List interfaceDeclaredMethods = ClassInfoHelper.collectMethodsFromInterfacesImplementedBy(mixinClass);
113             List sortedMethodList = ClassInfoHelper.createInterfaceDefinedMethodList(
114                     mixinClass, interfaceDeclaredMethods
115             );
116             for (Iterator iterator = sortedMethodList.iterator(); iterator.hasNext();) {
117                 MethodInfo methodInfo = (MethodInfo) iterator.next();
118                 m_methodsToIntroduce.add(methodInfo);
119             }
120         }
121 
122         m_mixinImplClassName = mixinClass.getName();
123         m_loaderRef = new WeakReference(mixinClass.getClassLoader());
124         m_systemDefinition = systemDef;
125         m_expressionInfos = new ExpressionInfo[]{};
126 
127         m_deploymentModel = deploymentModel;
128         m_isTransient = isTransient;
129 
130         // default factory
131         setFactoryClassName(DEFAULT_MIXIN_FACTORY);
132     }
133 
134     /***
135      * Sets the factory class name.
136      *
137      * @param factoryClassName
138      */
139     public void setFactoryClassName(final String factoryClassName) {
140         m_factoryClassName = factoryClassName;
141     }
142 
143     /***
144      * Returns the factory class name.
145      *
146      * @return
147      */
148     public String getFactoryClassName() {
149         return m_factoryClassName;
150     }
151 
152     /***
153      * Returns the methods to introduce.
154      *
155      * @return the methods to introduce
156      */
157     public List getMethodsToIntroduce() {
158         return m_methodsToIntroduce;
159     }
160 
161     /***
162      * Returns the deployment model.
163      *
164      * @return the deployment model
165      */
166     public DeploymentModel getDeploymentModel() {
167         return m_deploymentModel;
168     }
169 
170     /***
171      * Sets the deployment model.
172      *
173      * @param deploymentModel
174      */
175     public void setDeploymentModel(final DeploymentModel deploymentModel) {
176         m_deploymentModel = deploymentModel;
177     }
178 
179     /***
180      * Checks if the mixin is transient.
181      *
182      * @return
183      */
184     public boolean isTransient() {
185         return m_isTransient;
186     }
187 
188     /***
189      * Sets the mixin as transient.
190      *
191      * @param isTransient
192      */
193     public void setTransient(boolean isTransient) {
194         m_isTransient = isTransient;
195     }
196 
197     /***
198      * Returns the class info for the mixin impl.
199      *
200      * @return the class info
201      */
202     public ClassInfo getMixinImpl() {
203         return AsmClassInfo.getClassInfo(m_mixinImplClassName, (ClassLoader) m_loaderRef.get());
204     }
205 
206     /***
207      * Returns the expressions.
208      *
209      * @return the expressions array
210      */
211     public ExpressionInfo[] getExpressionInfos() {
212         return m_expressionInfos;
213     }
214 
215     /***
216      * Returns the class name of the interface.
217      *
218      * @return the class name of the interface
219      */
220     public List getInterfaceClassNames() {
221         return m_interfaceClassNames;
222     }
223 
224     /***
225      * Returns the attribute.
226      *
227      * @return the attribute
228      */
229     public String getAttribute() {
230         return m_attribute;
231     }
232 
233     /***
234      * Sets the attribute.
235      *
236      * @param attribute the attribute
237      */
238     public void setAttribute(final String attribute) {
239         m_attribute = attribute;
240     }
241 
242     /***
243      * Returns the system definition.
244      *
245      * @return the system definition
246      */
247     public SystemDefinition getSystemDefinition() {
248         return m_systemDefinition;
249     }
250 
251     /***
252      * Adds a new expression info.
253      *
254      * @param expression a new expression info
255      */
256     public void addExpressionInfo(final ExpressionInfo expression) {
257         final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length + 1];
258         java.lang.System.arraycopy(m_expressionInfos, 0, tmpExpressions, 0, m_expressionInfos.length);
259         tmpExpressions[m_expressionInfos.length] = expression;
260         m_expressionInfos = new ExpressionInfo[m_expressionInfos.length + 1];
261         java.lang.System.arraycopy(tmpExpressions, 0, m_expressionInfos, 0, tmpExpressions.length);
262     }
263 
264     /***
265      * Adds an array with new expression infos.
266      *
267      * @param expressions an array with new expression infos
268      */
269     public void addExpressionInfos(final ExpressionInfo[] expressions) {
270         final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length + expressions.length];
271         java.lang.System.arraycopy(m_expressionInfos, 0, tmpExpressions, 0, m_expressionInfos.length);
272         java.lang.System.arraycopy(expressions, 0, tmpExpressions, m_expressionInfos.length, expressions.length);
273         m_expressionInfos = new ExpressionInfo[m_expressionInfos.length + expressions.length];
274         java.lang.System.arraycopy(tmpExpressions, 0, m_expressionInfos, 0, tmpExpressions.length);
275     }
276 
277     /***
278      * Defines system mixins.
279      *
280      * @param loader
281      * @return
282      */
283     private ClassInfo defineSystemMixin(final ClassLoader loader) {
284         // if advisable impl mixin get the class info from the AsmClassInfo to keep the methods starting with aw$
285         ClassInfo mixinClass = AsmClassInfo.getClassInfo(AdvisableImpl.class.getName(), loader);
286         MethodInfo[] methods = mixinClass.getMethods();
287         for (int i = 0; i < methods.length; i++) {
288             MethodInfo method = methods[i];
289             if (method.getName().startsWith(TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
290                 || method.getName().startsWith("aw_")) {//aw$ not reachable in IDEs without AW source code
291                 m_methodsToIntroduce.add(method);
292             }
293         }
294         m_interfaceClassNames.add(Advisable.class.getName());
295         return mixinClass;
296     }
297 
298     /***
299      * Checks if the mixin is a system mixin.
300      *
301      * @param mixinClass
302      * @return
303      */
304     private boolean isSystemMixin(final ClassInfo mixinClass) {
305         return mixinClass.getName().equals(AdvisableImpl.class.getName());
306     }
307 
308     /***
309      * Adds a new parameter to the mixin.
310      *
311      * @param name  the name of the parameter
312      * @param value the value for the parameter
313      */
314     public void addParameter(final String name, final String value) {
315         m_parameters.put(name, value);
316     }
317 
318     /***
319      * Returns the parameters as a Map.
320      *
321      * @return the parameters
322      */
323     public Map getParameters() {
324         return m_parameters;
325     }
326 
327 }