001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.aspectwerkz.definition;
005:
006: import com.tc.aspectwerkz.DeploymentModel;
007: import com.tc.aspectwerkz.expression.ExpressionInfo;
008: import com.tc.aspectwerkz.aspect.DefaultMixinFactory;
009: import com.tc.aspectwerkz.intercept.Advisable;
010: import com.tc.aspectwerkz.intercept.AdvisableImpl;
011: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
012: import com.tc.aspectwerkz.reflect.ClassInfoHelper;
013: import com.tc.aspectwerkz.reflect.MethodInfo;
014: import com.tc.aspectwerkz.reflect.ClassInfo;
015: import com.tc.aspectwerkz.transform.TransformationConstants;
016:
017: import java.util.ArrayList;
018: import java.util.Iterator;
019: import java.util.List;
020: import java.util.Map;
021: import java.util.HashMap;
022: import java.lang.ref.WeakReference;
023:
024: /**
025: * Definition for the mixin construct.
026: *
027: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
028: */
029: public class MixinDefinition {
030:
031: private final static String DEFAULT_MIXIN_FACTORY = DefaultMixinFactory.class
032: .getName().replace('/', '.');
033: /**
034: * The deployment model for the mixin.
035: */
036: private DeploymentModel m_deploymentModel;
037:
038: /**
039: * Flags the mixin as transient.
040: */
041: private boolean m_isTransient;
042:
043: /**
044: * The introduced methods info list.
045: */
046: private final List m_methodsToIntroduce = new ArrayList();
047:
048: /**
049: * The interface classes name.
050: */
051: private final List m_interfaceClassNames = new ArrayList();
052:
053: /**
054: * The class name for the mixin impl.
055: */
056: private final String m_mixinImplClassName;
057:
058: /**
059: * The class loader.
060: */
061: private final WeakReference m_loaderRef;
062:
063: /**
064: * The mixin expressions.
065: */
066: private ExpressionInfo[] m_expressionInfos = new ExpressionInfo[] {};
067:
068: /**
069: * The attribute for the mixin.
070: */
071: private String m_attribute = "";
072:
073: /**
074: * The factory class name.
075: */
076: private String m_factoryClassName;
077:
078: /**
079: * The system definition.
080: */
081: private SystemDefinition m_systemDefinition;
082:
083: /**
084: * The parameters passed to the mixin at definition time.
085: */
086: private Map m_parameters = new HashMap();
087:
088: /**
089: * Construct a new definition for mixin.
090: *
091: * @param mixinClass the mixin class
092: * @param deploymentModel mixin deployment model
093: * @param isTransient transient flag
094: * @param systemDef the system definition
095: */
096: public MixinDefinition(ClassInfo mixinClass,
097: final DeploymentModel deploymentModel,
098: final boolean isTransient, final SystemDefinition systemDef) {
099: if (isSystemMixin(mixinClass)) {
100: mixinClass = defineSystemMixin(mixinClass.getClassLoader());
101: } else {
102: List allInterfaces = ClassInfoHelper
103: .collectInterfaces(mixinClass);
104: for (Iterator iterator = allInterfaces.iterator(); iterator
105: .hasNext();) {
106: ClassInfo interfaceInfo = (ClassInfo) iterator.next();
107: m_interfaceClassNames.add(interfaceInfo.getName());
108: }
109:
110: List interfaceDeclaredMethods = ClassInfoHelper
111: .collectMethodsFromInterfacesImplementedBy(mixinClass);
112: List sortedMethodList = ClassInfoHelper
113: .createInterfaceDefinedMethodList(mixinClass,
114: interfaceDeclaredMethods);
115: for (Iterator iterator = sortedMethodList.iterator(); iterator
116: .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,
204: (ClassLoader) m_loaderRef.get());
205: }
206:
207: /**
208: * Returns the expressions.
209: *
210: * @return the expressions array
211: */
212: public ExpressionInfo[] getExpressionInfos() {
213: return m_expressionInfos;
214: }
215:
216: /**
217: * Returns the class name of the interface.
218: *
219: * @return the class name of the interface
220: */
221: public List getInterfaceClassNames() {
222: return m_interfaceClassNames;
223: }
224:
225: /**
226: * Returns the attribute.
227: *
228: * @return the attribute
229: */
230: public String getAttribute() {
231: return m_attribute;
232: }
233:
234: /**
235: * Sets the attribute.
236: *
237: * @param attribute the attribute
238: */
239: public void setAttribute(final String attribute) {
240: m_attribute = attribute;
241: }
242:
243: /**
244: * Returns the system definition.
245: *
246: * @return the system definition
247: */
248: public SystemDefinition getSystemDefinition() {
249: return m_systemDefinition;
250: }
251:
252: /**
253: * Adds a new expression info.
254: *
255: * @param expression a new expression info
256: */
257: public void addExpressionInfo(final ExpressionInfo expression) {
258: final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length + 1];
259: java.lang.System.arraycopy(m_expressionInfos, 0,
260: tmpExpressions, 0, m_expressionInfos.length);
261: tmpExpressions[m_expressionInfos.length] = expression;
262: m_expressionInfos = new ExpressionInfo[m_expressionInfos.length + 1];
263: java.lang.System.arraycopy(tmpExpressions, 0,
264: m_expressionInfos, 0, tmpExpressions.length);
265: }
266:
267: /**
268: * Adds an array with new expression infos.
269: *
270: * @param expressions an array with new expression infos
271: */
272: public void addExpressionInfos(final ExpressionInfo[] expressions) {
273: final ExpressionInfo[] tmpExpressions = new ExpressionInfo[m_expressionInfos.length
274: + expressions.length];
275: java.lang.System.arraycopy(m_expressionInfos, 0,
276: tmpExpressions, 0, m_expressionInfos.length);
277: java.lang.System.arraycopy(expressions, 0, tmpExpressions,
278: m_expressionInfos.length, expressions.length);
279: m_expressionInfos = new ExpressionInfo[m_expressionInfos.length
280: + expressions.length];
281: java.lang.System.arraycopy(tmpExpressions, 0,
282: m_expressionInfos, 0, tmpExpressions.length);
283: }
284:
285: /**
286: * Defines system mixins.
287: *
288: * @param loader
289: * @return
290: */
291: private ClassInfo defineSystemMixin(final ClassLoader loader) {
292: // if advisable impl mixin getDefault the class info from the AsmClassInfo to keep the methods starting with aw$
293: ClassInfo mixinClass = AsmClassInfo.getClassInfo(
294: AdvisableImpl.class.getName(), loader);
295: MethodInfo[] methods = mixinClass.getMethods();
296: for (int i = 0; i < methods.length; i++) {
297: MethodInfo method = methods[i];
298: if (method.getName().startsWith(
299: TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
300: || method.getName().startsWith("aw_")) {//aw$ not reachable in IDEs without AW source code
301: m_methodsToIntroduce.add(method);
302: }
303: }
304: m_interfaceClassNames.add(Advisable.class.getName());
305: return mixinClass;
306: }
307:
308: /**
309: * Checks if the mixin is a system mixin.
310: *
311: * @param mixinClass
312: * @return
313: */
314: private boolean isSystemMixin(final ClassInfo mixinClass) {
315: return mixinClass.getName().equals(
316: AdvisableImpl.class.getName());
317: }
318:
319: /**
320: * Adds a new parameter to the mixin.
321: *
322: * @param name the name of the parameter
323: * @param value the value for the parameter
324: */
325: public void addParameter(final String name, final String value) {
326: m_parameters.put(name, value);
327: }
328:
329: /**
330: * Returns the parameters as a Map.
331: *
332: * @return the parameters
333: */
334: public Map getParameters() {
335: return m_parameters;
336: }
337:
338: }
|