001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.definition;
008:
009: import org.codehaus.aspectwerkz.expression.ExpressionInfo;
010: import org.codehaus.aspectwerkz.reflect.ClassInfo;
011: import org.codehaus.aspectwerkz.reflect.ClassInfoHelper;
012: import org.codehaus.aspectwerkz.reflect.MethodInfo;
013: import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
014: import org.codehaus.aspectwerkz.DeploymentModel;
015: import org.codehaus.aspectwerkz.aspect.DefaultMixinFactory;
016: import org.codehaus.aspectwerkz.intercept.AdvisableImpl;
017: import org.codehaus.aspectwerkz.intercept.Advisable;
018: import org.codehaus.aspectwerkz.transform.TransformationConstants;
019:
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.HashMap;
025: import java.lang.ref.WeakReference;
026:
027: /**
028: * Definition for the mixin construct.
029: *
030: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
031: */
032: public class MixinDefinition {
033:
034: private final static String DEFAULT_MIXIN_FACTORY = DefaultMixinFactory.class
035: .getName().replace('/', '.');
036: /**
037: * The deployment model for the mixin.
038: */
039: private DeploymentModel m_deploymentModel;
040:
041: /**
042: * Flags the mixin as transient.
043: */
044: private boolean m_isTransient;
045:
046: /**
047: * The introduced methods info list.
048: */
049: private final List m_methodsToIntroduce = new ArrayList();
050:
051: /**
052: * The interface classes name.
053: */
054: private final List m_interfaceClassNames = new ArrayList();
055:
056: /**
057: * The class name for the mixin impl.
058: */
059: private final String m_mixinImplClassName;
060:
061: /**
062: * The class loader.
063: */
064: private final WeakReference m_loaderRef;
065:
066: /**
067: * The mixin expressions.
068: */
069: private ExpressionInfo[] m_expressionInfos = new ExpressionInfo[] {};
070:
071: /**
072: * The attribute for the mixin.
073: */
074: private String m_attribute = "";
075:
076: /**
077: * The factory class name.
078: */
079: private String m_factoryClassName;
080:
081: /**
082: * The system definition.
083: */
084: private SystemDefinition m_systemDefinition;
085:
086: /**
087: * The parameters passed to the mixin at definition time.
088: */
089: private Map m_parameters = new HashMap();
090:
091: /**
092: * Construct a new definition for mixin.
093: *
094: * @param mixinClass the mixin class
095: * @param deploymentModel mixin deployment model
096: * @param isTransient transient flag
097: * @param systemDef the system definition
098: */
099: public MixinDefinition(ClassInfo mixinClass,
100: final DeploymentModel deploymentModel,
101: final boolean isTransient, final SystemDefinition systemDef) {
102: if (isSystemMixin(mixinClass)) {
103: mixinClass = defineSystemMixin(mixinClass.getClassLoader());
104: } else {
105: List allInterfaces = ClassInfoHelper
106: .collectInterfaces(mixinClass);
107: for (Iterator iterator = allInterfaces.iterator(); iterator
108: .hasNext();) {
109: ClassInfo interfaceInfo = (ClassInfo) iterator.next();
110: m_interfaceClassNames.add(interfaceInfo.getName());
111: }
112:
113: List interfaceDeclaredMethods = ClassInfoHelper
114: .collectMethodsFromInterfacesImplementedBy(mixinClass);
115: List sortedMethodList = ClassInfoHelper
116: .createInterfaceDefinedMethodList(mixinClass,
117: interfaceDeclaredMethods);
118: for (Iterator iterator = sortedMethodList.iterator(); iterator
119: .hasNext();) {
120: MethodInfo methodInfo = (MethodInfo) iterator.next();
121: m_methodsToIntroduce.add(methodInfo);
122: }
123: }
124:
125: m_mixinImplClassName = mixinClass.getName();
126: m_loaderRef = new WeakReference(mixinClass.getClassLoader());
127: m_systemDefinition = systemDef;
128: m_expressionInfos = new ExpressionInfo[] {};
129:
130: m_deploymentModel = deploymentModel;
131: m_isTransient = isTransient;
132:
133: // default factory
134: setFactoryClassName(DEFAULT_MIXIN_FACTORY);
135: }
136:
137: /**
138: * Sets the factory class name.
139: *
140: * @param factoryClassName
141: */
142: public void setFactoryClassName(final String factoryClassName) {
143: m_factoryClassName = factoryClassName;
144: }
145:
146: /**
147: * Returns the factory class name.
148: *
149: * @return
150: */
151: public String getFactoryClassName() {
152: return m_factoryClassName;
153: }
154:
155: /**
156: * Returns the methods to introduce.
157: *
158: * @return the methods to introduce
159: */
160: public List getMethodsToIntroduce() {
161: return m_methodsToIntroduce;
162: }
163:
164: /**
165: * Returns the deployment model.
166: *
167: * @return the deployment model
168: */
169: public DeploymentModel getDeploymentModel() {
170: return m_deploymentModel;
171: }
172:
173: /**
174: * Sets the deployment model.
175: *
176: * @param deploymentModel
177: */
178: public void setDeploymentModel(final DeploymentModel deploymentModel) {
179: m_deploymentModel = deploymentModel;
180: }
181:
182: /**
183: * Checks if the mixin is transient.
184: *
185: * @return
186: */
187: public boolean isTransient() {
188: return m_isTransient;
189: }
190:
191: /**
192: * Sets the mixin as transient.
193: *
194: * @param isTransient
195: */
196: public void setTransient(boolean isTransient) {
197: m_isTransient = isTransient;
198: }
199:
200: /**
201: * Returns the class info for the mixin impl.
202: *
203: * @return the class info
204: */
205: public ClassInfo getMixinImpl() {
206: return AsmClassInfo.getClassInfo(m_mixinImplClassName,
207: (ClassLoader) m_loaderRef.get());
208: }
209:
210: /**
211: * Returns the expressions.
212: *
213: * @return the expressions array
214: */
215: public ExpressionInfo[] getExpressionInfos() {
216: return m_expressionInfos;
217: }
218:
219: /**
220: * Returns the class name of the interface.
221: *
222: * @return the class name of the interface
223: */
224: public List getInterfaceClassNames() {
225: return m_interfaceClassNames;
226: }
227:
228: /**
229: * Returns the attribute.
230: *
231: * @return the attribute
232: */
233: public String getAttribute() {
234: return m_attribute;
235: }
236:
237: /**
238: * Sets the attribute.
239: *
240: * @param attribute the attribute
241: */
242: public void setAttribute(final String attribute) {
243: m_attribute = attribute;
244: }
245:
246: /**
247: * Returns the system definition.
248: *
249: * @return the system definition
250: */
251: public SystemDefinition getSystemDefinition() {
252: return m_systemDefinition;
253: }
254:
255: /**
256: * Adds a new expression info.
257: *
258: * @param expression a new expression info
259: */
260: public void addExpressionInfo(final ExpressionInfo expression) {
261: final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length + 1];
262: java.lang.System.arraycopy(m_expressionInfos, 0,
263: tmpExpressions, 0, m_expressionInfos.length);
264: tmpExpressions[m_expressionInfos.length] = expression;
265: m_expressionInfos = new ExpressionInfo[m_expressionInfos.length + 1];
266: java.lang.System.arraycopy(tmpExpressions, 0,
267: m_expressionInfos, 0, tmpExpressions.length);
268: }
269:
270: /**
271: * Adds an array with new expression infos.
272: *
273: * @param expressions an array with new expression infos
274: */
275: public void addExpressionInfos(final ExpressionInfo[] expressions) {
276: final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length
277: + expressions.length];
278: java.lang.System.arraycopy(m_expressionInfos, 0,
279: tmpExpressions, 0, m_expressionInfos.length);
280: java.lang.System.arraycopy(expressions, 0, tmpExpressions,
281: m_expressionInfos.length, expressions.length);
282: m_expressionInfos = new ExpressionInfo[m_expressionInfos.length
283: + expressions.length];
284: java.lang.System.arraycopy(tmpExpressions, 0,
285: m_expressionInfos, 0, tmpExpressions.length);
286: }
287:
288: /**
289: * Defines system mixins.
290: *
291: * @param loader
292: * @return
293: */
294: private ClassInfo defineSystemMixin(final ClassLoader loader) {
295: // if advisable impl mixin get the class info from the AsmClassInfo to keep the methods starting with aw$
296: ClassInfo mixinClass = AsmClassInfo.getClassInfo(
297: AdvisableImpl.class.getName(), loader);
298: MethodInfo[] methods = mixinClass.getMethods();
299: for (int i = 0; i < methods.length; i++) {
300: MethodInfo method = methods[i];
301: if (method.getName().startsWith(
302: TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
303: || method.getName().startsWith("aw_")) {//aw$ not reachable in IDEs without AW source code
304: m_methodsToIntroduce.add(method);
305: }
306: }
307: m_interfaceClassNames.add(Advisable.class.getName());
308: return mixinClass;
309: }
310:
311: /**
312: * Checks if the mixin is a system mixin.
313: *
314: * @param mixinClass
315: * @return
316: */
317: private boolean isSystemMixin(final ClassInfo mixinClass) {
318: return mixinClass.getName().equals(
319: AdvisableImpl.class.getName());
320: }
321:
322: /**
323: * Adds a new parameter to the mixin.
324: *
325: * @param name the name of the parameter
326: * @param value the value for the parameter
327: */
328: public void addParameter(final String name, final String value) {
329: m_parameters.put(name, value);
330: }
331:
332: /**
333: * Returns the parameters as a Map.
334: *
335: * @return the parameters
336: */
337: public Map getParameters() {
338: return m_parameters;
339: }
340:
341: }
|