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
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
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_")) {
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 }