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.aspect.container;
005:
006: import com.tc.asm.ClassWriter;
007: import com.tc.asm.MethodVisitor;
008: import com.tc.asm.Opcodes;
009:
010: import com.tc.aspectwerkz.reflect.impl.asm.AsmClassInfo;
011: import com.tc.aspectwerkz.reflect.ClassInfo;
012: import com.tc.aspectwerkz.reflect.ConstructorInfo;
013: import com.tc.aspectwerkz.transform.Properties;
014: import com.tc.aspectwerkz.transform.TransformationConstants;
015: import com.tc.aspectwerkz.transform.inlining.AsmHelper;
016: import com.tc.aspectwerkz.util.Strings;
017:
018: import java.io.IOException;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: /**
024: * Create a factory class for different aspect life cycle models.
025: * <p/>
026: * Each model ends in instantiating the aspect thru "new XAspect()" if there is no aspect container, or thru
027: * keeping a reference to the container and delegating to it thru container.aspectOf(..).
028: * The container itself is created with a one per factory basis (thus controlled by QName) thru
029: * "new XContainer()" or "new XContainer(aspectClass, aopSystemClassLoader, String uuid, String aspectQName, Map aspectParam)"
030: * <p/>
031: * Each model has the aspectOf(..) method, and the "hasAspect(..)" method.
032: * <p/>
033: * PerObject has a bind(object) method suitable for perTarget / perThis, that delegates to a supposely implemented
034: * interface in the target object itself (to avoid a map)
035: * <p/>
036: * PerCflowX has a bind(thread) / unbind(thread) suitable for perCflow / perCflowBelow.
037: * <p/>
038: * TODO: none is synchronized. AspectJ does not synchronize neither...
039: *
040: * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
041: * @author Jonas Bonér
042: */
043: public abstract class AbstractAspectFactoryCompiler implements Opcodes,
044: TransformationConstants {
045:
046: final static Artifact[] EMPTY_ARTIFACT_ARRAY = new Artifact[0];
047:
048: private final ClassLoader m_loader;
049:
050: protected String m_aspectFactoryClassName;
051: protected String[] m_interfaces = null;
052: protected final String m_aspectQualifiedName;
053: protected final String m_aspectClassName;
054: protected final String m_aspectClassSignature;
055: protected final String m_aspectContainerClassName;
056: protected final boolean m_hasAspectContainer;
057:
058: private final String m_uuid;
059: private boolean m_hasParameters;
060: private String m_rawParameters;
061: private Map m_parametersLazy;
062:
063: protected ClassWriter m_cw;
064: protected MethodVisitor m_clinit;
065:
066: public AbstractAspectFactoryCompiler(String uuid,
067: String aspectClassName, String aspectQualifiedName,
068: String containerClassName, String rawParameters,
069: ClassLoader loader) {
070: m_uuid = uuid;
071: m_aspectClassName = aspectClassName.replace('.', '/');
072: m_aspectClassSignature = 'L' + m_aspectClassName + ';';
073: m_aspectQualifiedName = aspectQualifiedName;
074: m_aspectFactoryClassName = AspectFactoryManager
075: .getAspectFactoryClassName(m_aspectClassName,
076: m_aspectQualifiedName);
077: if (containerClassName != null) {
078: m_aspectContainerClassName = containerClassName.replace(
079: '.', '/');
080: m_hasAspectContainer = true;
081: } else {
082: m_aspectContainerClassName = null;
083: m_hasAspectContainer = false;
084: }
085: if (rawParameters != null) {
086: m_rawParameters = rawParameters;
087: m_hasParameters = true;
088: } else {
089: m_rawParameters = null;
090: m_hasParameters = false;
091: }
092: m_loader = loader;
093: }
094:
095: private Map getParameters() {
096: if (m_parametersLazy == null) {
097: Map map;
098: if (m_rawParameters != null) {
099: map = new HashMap();
100: String[] raw = Strings.splitString(m_rawParameters,
101: DELIMITER);
102: for (int i = 0; i < raw.length; i++) {
103: if (i < raw.length) {
104: map.put(raw[i], raw[++i]);
105: }
106: }
107: } else {
108: map = new HashMap(0);
109: }
110: m_parametersLazy = map;
111: }
112: return m_parametersLazy;
113: }
114:
115: public Artifact compile() {
116: m_cw = AsmHelper.newClassWriter(true);
117:
118: m_cw.visit(AsmHelper.JAVA_VERSION, ACC_PUBLIC,
119: m_aspectFactoryClassName, null, OBJECT_CLASS_NAME,
120: m_interfaces);
121:
122: // create a CLASS field to host this factory class
123: m_cw.visitField(ACC_STATIC + ACC_PRIVATE,
124: FACTORY_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE, null,
125: null);
126:
127: // create a clinit method
128: m_clinit = m_cw.visitMethod(ACC_STATIC, CLINIT_METHOD_NAME,
129: CLINIT_METHOD_SIGNATURE, null, null);
130:
131: // init the CLASS field
132: m_clinit.visitLdcInsn(m_aspectFactoryClassName
133: .replace('/', '.'));
134: m_clinit.visitMethodInsn(INVOKESTATIC, CLASS_CLASS,
135: FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
136: m_clinit.visitFieldInsn(PUTSTATIC, m_aspectFactoryClassName,
137: FACTORY_CLASS_FIELD_NAME, CLASS_CLASS_SIGNATURE);
138:
139: if (m_hasParameters) {
140: createParametersFieldAndClinit();
141: }
142: if (m_hasAspectContainer) {
143: createAspectContainerFieldAndClinit();
144: }
145:
146: createAspectOf();
147: createHasAspect();
148: createOtherArtifacts();
149:
150: m_clinit.visitInsn(RETURN);
151: m_clinit.visitMaxs(0, 0);
152:
153: Artifact artifact = new Artifact(m_aspectFactoryClassName, m_cw
154: .toByteArray());
155:
156: if (Properties.DUMP_JIT_FACTORIES)
157: try {
158: AsmHelper.dumpClass(Properties.DUMP_DIR_FACTORIES,
159: artifact.className, artifact.bytecode);
160: } catch (IOException e) {
161: }
162: return artifact;
163: }
164:
165: protected abstract void createAspectOf();
166:
167: protected abstract void createHasAspect();
168:
169: protected abstract void createOtherArtifacts();
170:
171: private void createParametersFieldAndClinit() {
172: m_cw.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL,
173: FACTORY_PARAMS_FIELD_NAME, MAP_CLASS_SIGNATURE, null,
174: null);
175:
176: m_clinit.visitTypeInsn(NEW, HASH_MAP_CLASS_NAME);
177: m_clinit.visitInsn(DUP);
178: m_clinit.visitMethodInsn(INVOKESPECIAL, HASH_MAP_CLASS_NAME,
179: INIT_METHOD_NAME, NO_PARAM_RETURN_VOID_SIGNATURE);
180: for (Iterator iterator = getParameters().entrySet().iterator(); iterator
181: .hasNext();) {
182: m_clinit.visitInsn(DUP);
183: Map.Entry entry = (Map.Entry) iterator.next();
184: m_clinit.visitLdcInsn(entry.getKey());
185: m_clinit.visitLdcInsn(entry.getValue());
186: m_clinit.visitMethodInsn(INVOKEINTERFACE, MAP_CLASS_NAME,
187: PUT_METHOD_NAME, PUT_METHOD_SIGNATURE);
188: m_clinit.visitInsn(POP);
189: }
190: m_clinit.visitFieldInsn(PUTSTATIC, m_aspectFactoryClassName,
191: FACTORY_PARAMS_FIELD_NAME, MAP_CLASS_SIGNATURE);
192: }
193:
194: private void createAspectContainerFieldAndClinit() {
195: m_cw.visitField(ACC_PRIVATE + ACC_STATIC,
196: FACTORY_CONTAINER_FIELD_NAME,
197: ASPECT_CONTAINER_CLASS_SIGNATURE, null, null);
198:
199: //support 2 different ctor for AspectContainer impl.
200: ClassInfo containerClassInfo = AsmClassInfo.getClassInfo(
201: m_aspectContainerClassName, m_loader);
202: boolean hasConstructor = false;
203: for (int i = 0; i < containerClassInfo.getConstructors().length; i++) {
204: ConstructorInfo constructorInfo = containerClassInfo
205: .getConstructors()[i];
206: if (ASPECT_CONTAINER_OPTIONAL_INIT_SIGNATURE
207: .equals(constructorInfo.getSignature())) {
208: hasConstructor = true;
209: break;
210: }
211: //TODO: check for no-arg ctor to avoid verify error and report error
212: }
213: m_clinit.visitTypeInsn(NEW, m_aspectContainerClassName);
214: m_clinit.visitInsn(DUP);
215: if (hasConstructor) {
216: m_clinit.visitLdcInsn(m_aspectClassName.replace('/', '.'));
217: m_clinit.visitMethodInsn(INVOKESTATIC, CLASS_CLASS,
218: FOR_NAME_METHOD_NAME, FOR_NAME_METHOD_SIGNATURE);
219: //Note have access to the CL that defines the aspect (can be child of aspect CL)
220: m_clinit.visitFieldInsn(GETSTATIC,
221: m_aspectFactoryClassName, FACTORY_CLASS_FIELD_NAME,
222: CLASS_CLASS_SIGNATURE);
223: m_clinit.visitMethodInsn(INVOKEVIRTUAL, CLASS_CLASS,
224: GETCLASSLOADER_METHOD_NAME,
225: CLASS_CLASS_GETCLASSLOADER_METHOD_SIGNATURE);
226: m_clinit.visitLdcInsn(m_uuid);
227: m_clinit.visitLdcInsn(m_aspectQualifiedName);
228: if (m_hasParameters) {
229: m_clinit.visitFieldInsn(GETSTATIC,
230: m_aspectFactoryClassName,
231: FACTORY_PARAMS_FIELD_NAME, MAP_CLASS_SIGNATURE);
232: } else {
233: m_clinit.visitInsn(ACONST_NULL);
234: }
235: m_clinit.visitMethodInsn(INVOKESPECIAL,
236: m_aspectContainerClassName, INIT_METHOD_NAME,
237: ASPECT_CONTAINER_OPTIONAL_INIT_SIGNATURE);
238: } else {
239: m_clinit.visitMethodInsn(INVOKESPECIAL,
240: m_aspectContainerClassName, INIT_METHOD_NAME,
241: NO_PARAM_RETURN_VOID_SIGNATURE);
242: }
243: m_clinit.visitFieldInsn(PUTSTATIC, m_aspectFactoryClassName,
244: FACTORY_CONTAINER_FIELD_NAME,
245: ASPECT_CONTAINER_CLASS_SIGNATURE);
246: }
247: }
|