001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.generation.generator.home;
018:
019: import org.objectweb.asm.ClassVisitor;
020: import org.objectweb.asm.ClassWriter;
021: import org.objectweb.asm.CodeVisitor;
022: import org.objectweb.asm.Constants;
023: import org.objectweb.asm.Label;
024: import org.objectweb.asm.Type;
025: import org.objectweb.jorm.lib.JormPathHelper;
026: import org.objectweb.jorm.metainfo.api.Class;
027: import org.objectweb.jorm.metainfo.api.ClassRef;
028: import org.objectweb.jorm.metainfo.api.GenClassMapping;
029: import org.objectweb.jorm.metainfo.api.GenClassRef;
030: import org.objectweb.jorm.metainfo.api.MetaObject;
031: import org.objectweb.jorm.metainfo.api.NameDef;
032: import org.objectweb.jorm.metainfo.api.ReferenceMapping;
033: import org.objectweb.jorm.type.api.PType;
034: import org.objectweb.speedo.api.SpeedoException;
035: import org.objectweb.speedo.api.SpeedoProperties;
036: import org.objectweb.speedo.generation.enhancer.common.Util;
037: import org.objectweb.speedo.generation.generator.lib.AbstractSpeedoGenerator;
038: import org.objectweb.speedo.generation.lib.NamingRules;
039: import org.objectweb.speedo.lib.Personality;
040: import org.objectweb.speedo.mapper.lib.Object2StringSerializer;
041: import org.objectweb.speedo.metadata.SpeedoClass;
042: import org.objectweb.speedo.metadata.SpeedoField;
043: import org.objectweb.speedo.metadata.SpeedoPredefinedQuery;
044: import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
045: import org.objectweb.speedo.mim.api.StateItf;
046: import org.objectweb.speedo.mim.api.PersistentObjectItf;
047: import org.objectweb.speedo.tools.StringReplace;
048:
049: import java.io.FileOutputStream;
050: import java.util.Collection;
051: import java.util.HashSet;
052: import java.util.Iterator;
053: import java.util.List;
054: import java.util.Map;
055: import java.util.Properties;
056:
057: /**
058: *
059: * @author S.Chassande-Barrioz
060: */
061: public abstract class HomeGenerator extends AbstractSpeedoGenerator
062: implements Constants {
063:
064: public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
065: + ".generation.generator.homes";
066:
067: public final static String TEMPLATE_NAME = TEMPLATE_DIR
068: + ".home.Home";
069:
070: /**
071: * Provides the class to be inherited by the generated Home.
072: * @return The Java Class metaobject.
073: */
074: protected abstract java.lang.Class getSuperClass();
075:
076: /**
077: * Provides the class to be used by the generated Home for query creation.
078: * @return The Java Class metaobject.
079: */
080: protected abstract java.lang.Class getQueryClass();
081:
082: public HomeGenerator(Personality p) {
083: super (p);
084: }
085:
086: // IMPLEMENTATION OF THE GeneratorComponent INTERFACE //
087: //----------------------------------------------------//
088:
089: public boolean init() throws SpeedoException {
090: logger = scp.loggerFactory.getLogger(LOGGER_NAME);
091: return !scp.getXmldescriptor().isEmpty();
092: }
093:
094: public void generate(SpeedoClass sClass, String fileName)
095: throws SpeedoException {
096:
097: final ClassWriter cv = new ClassWriter(true);
098: Map ctx = getContextAsMap(sClass);
099: HomeContext gc = new HomeContext(sClass, cv, ctx);
100: //create the class
101: cv.visit(V1_1, ACC_PUBLIC + ACC_SUPER + ACC_ABSTRACT,
102: gc.xHomeJCN, gc.super ClassJCN, new String[] {},
103: gc.xHomeJCN);
104: generateFinalStaticFields(gc);
105: generateStaticClause(gc);
106: generateClassMethod(gc);
107: generatePersonalityMethods(gc);
108: generateNoArgConstructor(gc);
109: generateNewSpeedoPOInstance(gc);
110: generateGetVersioningStrategy(gc);
111: generateIsDetachable(gc);
112: generateIsAbstract(gc);
113: generateGetClassProperties(gc);
114: generateWriteIntention(gc);
115: generateActiveUserCache(gc);
116: generateIniSHMethod(gc);
117: cv.visitEnd();
118:
119: try {
120: FileOutputStream fos = new FileOutputStream(fileName);
121: fos.write(cv.toByteArray());
122: fos.close();
123: } catch (Exception e) {
124: throw new SpeedoException(
125: "Problem while generating PAccessor.", e);
126: }
127: }
128:
129: private void getJormConfig(SpeedoClass sc,
130: Properties classProperties) throws SpeedoException {
131: //Build the map
132: // Put the binder class name of the current persistent class
133: String id = JormPathHelper.getPath(sc.jormclass);
134: NameDef nd = getClassNameDef(sc.jormclass);
135: jormConfigs(nd, sc, sc.jormclass, id, classProperties);
136:
137: //Put the binder class name for each reference field
138: SpeedoXMLDescriptor xml = sc.moPackage.xmlDescriptor;
139: for (Iterator it = sc.jormclass.getAllFields().iterator(); it
140: .hasNext();) {
141: Object o = it.next();
142: if (o instanceof ClassRef) {
143: nd = getRefNameDef((ClassRef) o, sc.jormclass);
144: id = JormPathHelper.getPath(((ClassRef) o));
145: SpeedoClass tsc = xml.getSpeedoClass(((ClassRef) o)
146: .getMOClass().getFQName(), true);
147: jormConfigs(nd, tsc, sc.jormclass, id, classProperties);
148: } else if (o instanceof GenClassRef) {
149: GenClassRef gcr = (GenClassRef) o;
150: nd = getRefNameDef(gcr, sc.jormclass);
151: id = JormPathHelper.getPath((GenClassRef) o, false);
152: jormConfigs(nd, sc, gcr, id, classProperties);
153: while (gcr.isGenClassRef()) {
154: gcr = gcr.getGenClassRef();
155: nd = getElemNameDef(gcr, sc.jormclass);
156: id = JormPathHelper.getPath(gcr, false);
157: jormConfigs(nd, sc, gcr, id, classProperties);
158: }
159: if (gcr.isClassRef()) {
160: ClassRef cr = gcr.getClassRef();
161: nd = getElemNameDef(gcr, sc.jormclass);
162: id = JormPathHelper.getPath(cr);
163: SpeedoClass tsc = xml.getSpeedoClass(cr
164: .getMOClass().getFQName(), true);
165: jormConfigs(nd, tsc, cr, id, classProperties);
166: }
167: }
168: }
169: }
170:
171: private void jormConfigs(NameDef nd, SpeedoClass targetClass,
172: MetaObject sourceMO, String key, Properties jormProp)
173: throws SpeedoException {
174: scp.nmf.getNamingManager(targetClass).getJormNamingConfig(nd,
175: targetClass, sourceMO, key, jormProp);
176: }
177:
178: private GenClassMapping getGenClassMapping(GenClassRef gcr,
179: Class clazz) throws SpeedoException {
180: String gcid = gcr.getGenClassId();
181: GenClassMapping gcm = getMapping(clazz)
182: .getGenClassMapping(gcid);
183: if (gcm == null) {
184: Class klass = clazz;
185: Collection super classes = klass.getSuperClasses();
186: while (gcm == null && !super classes.isEmpty()) {
187: klass = (Class) super classes.iterator().next();
188: gcm = getMapping(klass).getGenClassMapping(gcid);
189: super classes = klass.getSuperClasses();
190: }
191: }
192: if (gcm == null) {
193: throw new SpeedoException(
194: "No GenClassMapping found for the field " + gcid);
195: }
196: return gcm;
197: }
198:
199: private NameDef getRefNameDef(GenClassRef gcr, Class clazz)
200: throws SpeedoException {
201: return (NameDef) getGenClassMapping(gcr, clazz)
202: .getIdentifierMapping().getLinkedMO();
203: }
204:
205: private NameDef getElemNameDef(GenClassRef gcr, Class clazz)
206: throws SpeedoException {
207: return (NameDef) getGenClassMapping(gcr, clazz)
208: .getReferenceMapping().getLinkedMO();
209: }
210:
211: private ReferenceMapping getReferenceMapping(ClassRef cr,
212: Class clazz) throws SpeedoException {
213: String rid = cr.getName();
214: ReferenceMapping rm = getMapping(clazz).getClassMapping()
215: .getReferenceMapping(rid);
216: if (rm == null) {
217: Class klass = clazz;
218: Collection super classes = klass.getSuperClasses();
219: while (rm == null && !super classes.isEmpty()) {
220: klass = (Class) super classes.iterator().next();
221: rm = getMapping(klass).getClassMapping()
222: .getReferenceMapping(rid);
223: super classes = klass.getSuperClasses();
224: }
225: }
226: if (rm == null) {
227: throw new SpeedoException(
228: "No ReferenceMapping found for the field " + rid);
229: }
230: return rm;
231:
232: }
233:
234: private NameDef getRefNameDef(ClassRef cr, Class clazz)
235: throws SpeedoException {
236: return (NameDef) getReferenceMapping(cr, clazz).getLinkedMO();
237: }
238:
239: private void generateFinalStaticFields(HomeContext gc) {
240: //protected static final byte VERSIONING_STRATEGY = ${versioningStrategy.byteValue()};
241: gc.cv.visitField(ACC_PROTECTED + ACC_FINAL + ACC_STATIC,
242: "VERSIONING_STRATEGY", "B", gc.ctx
243: .get("versioningStrategy"), null);
244:
245: //public static final boolean DETACHABLE = $detachable;
246: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
247: "DETACHABLE", "Z", new Integer(gc.sc.isDetachable ? 1
248: : 0), null);
249:
250: //public static final String[] FIELD_NAMES = ${fieldsNamesArray};
251: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
252: "FIELD_NAMES", "[Ljava/lang/String;", null, null);
253: //public static final Class[] FIELD_TYPES = ${fieldsTypesArray};
254: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
255: "FIELD_TYPES", "[Ljava/lang/Class;", null, null);
256: //public static final byte[] FIELD_FLAGS = new byte[0];
257: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
258: "FIELD_FLAGS", "[B", null, null);
259: //public static final Class SUPER_CLASS = #if($hasSuperclass)#**#${superClassName}.class#else#**#null#end#**#;
260: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
261: "SUPER_CLASS", "Ljava/lang/Class;", null, null);
262:
263: for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
264: gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
265: gc.userCacheNames[ucIdx] + "_USER_CACHE_ID", "I",
266: new Integer(ucIdx), null);
267: }
268: }
269:
270: private void generateStaticClause(HomeContext gc) {
271: CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC, "<clinit>",
272: "()V", null, null);
273: final HashSet staticfieldNames = new HashSet();
274: generateFieldNamesInit(gc, cv);
275: generateFieldTypesInit(gc, staticfieldNames, cv);
276:
277: // Field flags
278: cv.visitInsn(ICONST_0);
279: cv.visitIntInsn(NEWARRAY, T_BYTE);
280: cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_FLAGS",
281: "[B");
282:
283: //Super class
284: if (gc.sc.getSuperClassName() == null) {
285: cv.visitInsn(ACONST_NULL);
286: } else {
287: generateDotClass(gc.sc.getSuperClassName(), gc,
288: staticfieldNames, cv);
289: }
290: cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "SUPER_CLASS",
291: "Ljava/lang/Class;");
292:
293: cv.visitInsn(RETURN);
294: cv.visitMaxs(0, 0);
295:
296: for (Iterator iter = staticfieldNames.iterator(); iter
297: .hasNext();) {
298: String fn = (String) iter.next();
299: gc.cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fn,
300: gc.classJT, null, null);
301: }
302: }
303:
304: private void generateFieldNamesInit(HomeContext gc, CodeVisitor cv) {
305: Collection fields = gc.sc.fields.values();
306: cv.visitIntInsn(BIPUSH, fields.size());
307: cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
308: int idx = 0;
309: for (Iterator it = fields.iterator(); it.hasNext();) {
310: SpeedoField sf = (SpeedoField) it.next();
311: cv.visitInsn(DUP);
312: Util.visitIntConstant(cv, idx);
313: cv.visitLdcInsn(sf.name);
314: cv.visitInsn(AASTORE);
315: idx++;
316: }
317: cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_NAMES",
318: "[Ljava/lang/String;");
319: }
320:
321: private void generateFieldTypesInit(HomeContext gc,
322: final HashSet staticfieldNames, CodeVisitor cv) {
323: Collection fields = gc.sc.fields.values();
324: cv.visitIntInsn(BIPUSH, fields.size());
325: cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
326:
327: final String fieldType = "TYPE";
328: int idx = 0;
329: for (Iterator it = fields.iterator(); it.hasNext();) {
330: cv.visitInsn(DUP);
331: Util.visitIntConstant(cv, idx);
332: idx++;
333: SpeedoField sf = (SpeedoField) it.next();
334: Type t = Type.getType(sf.type);
335: switch (t.getSort()) {
336: case Type.BOOLEAN:
337: cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean",
338: fieldType, gc.classJT);
339: break;
340: case Type.BYTE:
341: cv.visitFieldInsn(GETSTATIC, "java/lang/Byte",
342: fieldType, gc.classJT);
343: break;
344: case Type.CHAR:
345: cv.visitFieldInsn(GETSTATIC, "java/lang/Character",
346: fieldType, gc.classJT);
347: break;
348: case Type.DOUBLE:
349: cv.visitFieldInsn(GETSTATIC, "java/lang/Double",
350: fieldType, gc.classJT);
351: break;
352: case Type.FLOAT:
353: cv.visitFieldInsn(GETSTATIC, "java/lang/Float",
354: fieldType, gc.classJT);
355: break;
356: case Type.INT:
357: cv.visitFieldInsn(GETSTATIC, "java/lang/Integer",
358: fieldType, gc.classJT);
359: break;
360: case Type.LONG:
361: cv.visitFieldInsn(GETSTATIC, "java/lang/Long",
362: fieldType, gc.classJT);
363: break;
364: case Type.SHORT:
365: cv.visitFieldInsn(GETSTATIC, "java/lang/Short",
366: fieldType, gc.classJT);
367: break;
368: case Type.ARRAY:
369: String cn;
370: switch (t.getElementType().getSort()) {
371: case Type.BOOLEAN:
372: case Type.BYTE:
373: case Type.CHAR:
374: case Type.DOUBLE:
375: case Type.FLOAT:
376: case Type.INT:
377: case Type.LONG:
378: case Type.SHORT:
379: cn = t.getDescriptor();
380: break;
381: default:
382: cn = t.getElementType().getClassName();
383: break;
384: }
385: generateDotClass(cn, gc, staticfieldNames, cv);
386: break;
387: default:
388: generateDotClass(t.getClassName(), gc,
389: staticfieldNames, cv);
390: break;
391: }
392: cv.visitInsn(AASTORE);
393: }
394: cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_TYPES",
395: "[Ljava/lang/Class;");
396: }
397:
398: private void generateDotClass(final String className,
399: final HomeContext gc, final HashSet staticfieldNames,
400: final CodeVisitor cv) {
401: final String staticFieldName = "class$"
402: + StringReplace.replaceString("[", "array$", className)
403: .replace('.', '$');
404: cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN,
405: staticFieldName, gc.classJT);
406: staticfieldNames.add(staticFieldName);
407: //this type has not been already met
408: Label labelElse = new Label();
409: Label labelEnd = new Label();
410: cv.visitJumpInsn(IFNONNULL, labelElse);
411: {
412: cv.visitLdcInsn(className);
413: cv.visitMethodInsn(INVOKESTATIC, gc.classToWriteJCN,
414: "class$", "(Ljava/lang/String;)" + gc.classJT);
415: cv.visitInsn(DUP);
416: cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN,
417: staticFieldName, gc.classJT);
418: cv.visitJumpInsn(GOTO, labelEnd);
419: }
420: cv.visitLabel(labelElse);
421: {
422: cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN,
423: staticFieldName, gc.classJT);
424: }
425: cv.visitLabel(labelEnd);
426: }
427:
428: private void generateClassMethod(HomeContext gc) {
429: CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC + ACC_SYNTHETIC,
430: "class$", "(Ljava/lang/String;)Ljava/lang/Class;",
431: null, null);
432: Label labelTry = new Label();
433: cv.visitLabel(labelTry);
434: cv.visitVarInsn(ALOAD, 0);
435: cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
436: "(Ljava/lang/String;)Ljava/lang/Class;");
437: Label labelEndTry = new Label();
438: cv.visitLabel(labelEndTry);
439: cv.visitInsn(ARETURN);
440: Label labelCatch = new Label();
441: cv.visitLabel(labelCatch);
442: cv.visitVarInsn(ASTORE, 1);
443: cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
444: cv.visitInsn(DUP);
445: cv.visitVarInsn(ALOAD, 1);
446: cv.visitMethodInsn(INVOKEVIRTUAL,
447: "java/lang/ClassNotFoundException", "getMessage",
448: "()Ljava/lang/String;");
449: cv.visitMethodInsn(INVOKESPECIAL,
450: "java/lang/NoClassDefFoundError", "<init>",
451: "(Ljava/lang/String;)V");
452: cv.visitInsn(ATHROW);
453: cv.visitTryCatchBlock(labelTry, labelEndTry, labelCatch,
454: "java/lang/ClassNotFoundException");
455: cv.visitMaxs(0, 0);
456: }
457:
458: protected void generateNoArgConstructor(HomeContext gc) {
459: CodeVisitor mv = gc.cv.visitMethod(ACC_PUBLIC, "<init>", "()V",
460: null, null);
461: mv.visitVarInsn(ALOAD, 0);
462: mv.visitMethodInsn(INVOKESPECIAL, gc.super ClassJCN, "<init>",
463: "()V");
464: mv.visitInsn(RETURN);
465: mv.visitMaxs(0, 0);
466: }
467:
468: private void generateNewSpeedoPOInstance(HomeContext gc) {
469: //protected PersistentObjectItf newSpeedoPOInstance(Class clazz) {
470: CodeVisitor cv = gc.cv
471: .visitMethod(
472: ACC_PROTECTED,
473: "newSpeedoPOInstance",
474: "(Ljava/lang/Class;)Lorg/objectweb/speedo/mim/api/PersistentObjectItf;",
475: null, null);
476: if (gc.sc.isAbstract) {
477: cv.visitInsn(ACONST_NULL);
478: cv.visitInsn(ARETURN);
479: } else {
480: Label l0 = new Label();
481: cv.visitLabel(l0);
482: cv.visitTypeInsn(NEW, gc.xJCN);
483: cv.visitInsn(DUP);
484: cv.visitMethodInsn(INVOKESPECIAL, gc.xJCN, "<init>", "()V");
485: // cv.visitVarInsn(ASTORE, 2);
486: // cv.visitVarInsn(ALOAD, 2);
487: cv.visitTypeInsn(CHECKCAST,
488: "org/objectweb/speedo/mim/api/PersistentObjectItf");
489: Label l1 = new Label();
490: cv.visitLabel(l1);
491: cv.visitInsn(ARETURN);
492: Label l2 = new Label();
493: cv.visitLabel(l2);
494: cv.visitVarInsn(ASTORE, 2);
495: cv.visitTypeInsn(NEW, personality
496: .getUserRuntimeExceptionClassNameSlash());
497: cv.visitInsn(DUP);
498: cv.visitLdcInsn("Impossible to instanciate the class "
499: + gc.classToWriteJCN + ": ");
500: cv.visitVarInsn(ALOAD, 2);
501: cv.visitMethodInsn(INVOKESPECIAL, personality
502: .getUserRuntimeExceptionClassNameSlash(), "<init>",
503: "(Ljava/lang/String;Ljava/lang/Throwable;)V");
504: cv.visitInsn(ATHROW);
505: cv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
506: }
507: cv.visitMaxs(0, 0);
508: }
509:
510: private void generateGetVersioningStrategy(HomeContext gc) {
511: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
512: "getVersioningStrategy", "()B", null, null);
513: cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN,
514: "VERSIONING_STRATEGY", "B");
515: cv.visitInsn(IRETURN);
516: cv.visitMaxs(1, 1);
517: }
518:
519: private void generateIsDetachable(HomeContext gc) {
520: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
521: "isDetachable", "()Z", null, null);
522: cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, "DETACHABLE",
523: "Z");
524: cv.visitInsn(IRETURN);
525: cv.visitMaxs(1, 1);
526: }
527:
528: private void generateIsAbstract(HomeContext gc) {
529: if (gc.sc.isAbstract) {
530: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
531: "isAbstract", "()Z", null, null);
532: cv.visitInsn(ICONST_1);
533: cv.visitInsn(IRETURN);
534: cv.visitMaxs(1, 1);
535: }
536: }
537:
538: private void generateGetClassProperties(HomeContext gc)
539: throws SpeedoException {
540: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
541: "getClassProperties", "()Ljava/util/Properties;", null,
542: null);
543: cv.visitTypeInsn(NEW, "java/util/Properties");
544: cv.visitInsn(DUP);
545: cv.visitMethodInsn(INVOKESPECIAL, "java/util/Properties",
546: "<init>", "()V");
547: cv.visitVarInsn(ASTORE, 1);
548:
549: Properties classProperties = new Properties();
550: getJormConfig(gc.sc, classProperties);
551: String xmlFileName = gc.sc.moPackage.xmlDescriptor.xmlFile;
552: xmlFileName = StringReplace.replaceChar('/', '.', xmlFileName);
553: xmlFileName = StringReplace.replaceChar(fs, '.', xmlFileName);
554: classProperties.setProperty(
555: Object2StringSerializer.DESC_FILE_NAME_PROP,
556: xmlFileName);
557: for (Iterator it = classProperties.entrySet().iterator(); it
558: .hasNext();) {
559: Map.Entry me = (Map.Entry) it.next();
560: cv.visitVarInsn(ALOAD, 1);
561: cv.visitLdcInsn(me.getKey());
562: cv.visitLdcInsn(me.getValue());
563: cv
564: .visitMethodInsn(INVOKEVIRTUAL,
565: "java/util/Properties", "setProperty",
566: "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
567: cv.visitInsn(POP); //remove the result of the setProperty method
568: }
569:
570: cv.visitVarInsn(ALOAD, 1);
571: cv.visitInsn(ARETURN);
572: cv.visitMaxs(3, 2);
573: }
574:
575: private void generateWriteIntention(HomeContext gc) {
576: if (gc.userCacheNames.length == 0) {
577: return;
578: }
579: //public StateItf writeIntention(PersistentObjectItf sp, long[] fields, Object thinLock)
580: final String methodDesc = "("
581: + getJVMType(PersistentObjectItf.class) + "[J"
582: + getJVMType(Object.class) + ")"
583: + getJVMType(StateItf.class);
584: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC,
585: "writeIntention", methodDesc, null, null);
586: //StateItf sa = super.writeIntention(sp, fields, thinLock);
587: cv.visitVarInsn(ALOAD, 0);
588: cv.visitVarInsn(ALOAD, 1);
589: cv.visitVarInsn(ALOAD, 2);
590: cv.visitVarInsn(ALOAD, 3);
591: cv.visitMethodInsn(INVOKESPECIAL, gc.super ClassJCN,
592: "writeIntention", methodDesc);
593: cv.visitVarInsn(ASTORE, 4);
594:
595: //if (fields == null) {
596: cv.visitVarInsn(ALOAD, 2);
597: Label labelElse = new Label();
598: cv.visitJumpInsn(IFNONNULL, labelElse);
599: Label labelEnd = new Label();
600: {
601: //sa.indexFieldModified(0xffffffff, false);
602: cv.visitVarInsn(ALOAD, 4);
603: cv.visitLdcInsn(new Integer(0xffffffff));
604: cv.visitInsn(ICONST_0);
605: cv.visitMethodInsn(INVOKEINTERFACE,
606: getJVMClassName(StateItf.class),
607: "indexFieldModified", "(IZ)V");
608: cv.visitJumpInsn(GOTO, labelEnd);
609: }
610: cv.visitLabel(labelElse);
611: {
612: for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
613: String ucn = gc.userCacheNames[ucIdx];
614: List fields = (List) gc.ucn2sfs.get(ucn);
615: for (Iterator itf = fields.iterator(); itf.hasNext();) {
616: SpeedoField sf = (SpeedoField) itf.next();
617: //if ((fields[${f.jormFieldIdLongPos}] & ${f.jormFieldId}L) != 0) {
618: cv.visitVarInsn(ALOAD, 2);
619: Util.visitIntConstant(cv, sf.number / 64);
620: cv.visitInsn(LALOAD);
621: Util.visitLongConstant(cv, 1L << (sf.number % 64));
622: cv.visitInsn(LAND);
623: cv.visitInsn(LCONST_0);
624: cv.visitInsn(LCMP);
625: Label labelNext = new Label();
626: cv.visitJumpInsn(IFEQ, labelNext);
627: {
628: //sa.indexFieldModified(${ucn}_USER_CACHE_ID, false);
629: cv.visitVarInsn(ALOAD, 4);
630: Util.visitIntConstant(cv, ucIdx);
631: cv.visitInsn(ICONST_0);
632: cv.visitMethodInsn(INVOKEINTERFACE,
633: getJVMClassName(StateItf.class),
634: "indexFieldModified", "(IZ)V");
635: }
636: cv.visitLabel(labelNext);
637: }
638: }
639: }
640: cv.visitLabel(labelEnd);
641: //return sa;
642: cv.visitVarInsn(ALOAD, 4);
643: cv.visitInsn(ARETURN);
644: cv.visitMaxs(0, 0);
645: }
646:
647: private void generateActiveUserCache(HomeContext gc) {
648: if (gc.userCacheNames.length == 0) {
649: return;
650: }
651: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC,
652: "activeUserCache", "(Ljava/lang/String;)Z", null, null);
653:
654: //if (cacheName == null) {
655: cv.visitVarInsn(ALOAD, 1);
656: Label l0 = new Label();
657: cv.visitJumpInsn(IFNONNULL, l0);
658: {
659: //return false;
660: cv.visitInsn(ICONST_0);
661: cv.visitInsn(IRETURN);
662: }
663: cv.visitLabel(l0);
664: //} else if ("*".equals(cacheName)) {
665: cv.visitLdcInsn("*");
666: cv.visitVarInsn(ALOAD, 1);
667: cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals",
668: "(Ljava/lang/Object;)Z");
669: Label labelElse = new Label();
670: cv.visitJumpInsn(IFEQ, labelElse);
671: {
672: //foreach($ucn in $userCacheNames)
673: for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
674: //activeUserCache("$ucn");
675: cv.visitVarInsn(ALOAD, 0);
676: cv.visitLdcInsn(gc.userCacheNames[ucIdx]);
677: cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
678: "activeUserCache", "(Ljava/lang/String;)Z");
679: cv.visitInsn(POP);
680: }
681: //return true;
682: cv.visitInsn(ICONST_1);
683: cv.visitInsn(IRETURN);
684: }
685: cv.visitLabel(labelElse);
686: for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
687: final String ucn = gc.userCacheNames[ucIdx];
688: //} else if ("${ucn}".equals(cacheName)) {
689: cv.visitLdcInsn(ucn);
690: cv.visitVarInsn(ALOAD, 1);
691: cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String",
692: "equals", "(Ljava/lang/Object;)Z");
693: Label labelNext = new Label();
694: cv.visitJumpInsn(IFEQ, labelNext);
695: {
696: //this.addUserCache(cacheName, ${userCacheFieldNames.get($ucn)}, ${ucn}_USER_CACHE_ID);
697: cv.visitVarInsn(ALOAD, 0); //this
698: cv.visitVarInsn(ALOAD, 1); //cacheName parameter
699:
700: //parameter ${userCacheFieldNames.get($ucn)}
701: // new String[]{"f1", "f2"}
702: final List fields = (List) gc.ucn2sfs.get(ucn);
703: Util.visitIntConstant(cv, fields.size()); //Array size
704: cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
705: for (int fieldIdx = 0; fieldIdx < fields.size(); fieldIdx++) {
706: SpeedoField sf = (SpeedoField) fields.get(fieldIdx);
707: cv.visitInsn(DUP);
708: Util.visitIntConstant(cv, fieldIdx); //index
709: cv.visitLdcInsn(sf.name); //value = field name
710: cv.visitInsn(AASTORE);
711: }
712:
713: Util.visitIntConstant(cv, ucIdx); //${ucn}_USER_CACHE_ID
714: cv
715: .visitMethodInsn(
716: INVOKEVIRTUAL,
717: gc.classToWriteJCN,
718: "addUserCache",
719: "(Ljava/lang/String;[Ljava/lang/String;I)Lorg/objectweb/speedo/usercache/api/UserCache;");
720: cv.visitInsn(POP);
721: //return true;
722: cv.visitInsn(ICONST_1);
723: cv.visitInsn(IRETURN);
724: }
725: cv.visitLabel(labelNext);
726: }
727: //return false;
728: cv.visitInsn(ICONST_0);
729: cv.visitInsn(IRETURN);
730: cv.visitMaxs(0, 0);
731: }
732:
733: private void generateIniSHMethod(HomeContext gc) {
734: CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "initSH", "()V",
735: null, null);
736: String sqJCN = getJVMClassName(getQueryClass());
737: for (Iterator it = gc.sc.name2query.values().iterator(); it
738: .hasNext();) {
739: SpeedoPredefinedQuery q = (SpeedoPredefinedQuery) it.next();
740: //sq = new SpeedoQuery();
741: cv.visitTypeInsn(NEW, sqJCN);
742: cv.visitInsn(DUP);
743: cv.visitMethodInsn(INVOKESPECIAL, sqJCN, "<init>", "()V");
744: cv.visitVarInsn(ASTORE, 1); //Always use the same variable 1
745:
746: if (q.query != null) {
747: cv.visitVarInsn(ALOAD, 1);
748: cv.visitLdcInsn(q.query);
749: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "defineWith",
750: "(Ljava/lang/String;)V");
751: }
752: if (q.filter != null) {
753: cv.visitVarInsn(ALOAD, 1);
754: cv.visitLdcInsn(q.filter);
755: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setFilter",
756: "(Ljava/lang/String;)V");
757: }
758: if (q.declareImports != null) {
759: cv.visitVarInsn(ALOAD, 1);
760: cv.visitLdcInsn(q.declareImports);
761: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN,
762: "declareImports", "(Ljava/lang/String;)V");
763: }
764: if (q.declareParameters != null) {
765: cv.visitVarInsn(ALOAD, 1);
766: cv.visitLdcInsn(q.declareParameters);
767: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN,
768: "declareParameters", "(Ljava/lang/String;)V");
769: }
770: if (q.declareVariables != null) {
771: cv.visitVarInsn(ALOAD, 1);
772: cv.visitLdcInsn(q.declareVariables);
773: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN,
774: "declareVariables", "(Ljava/lang/String;)V");
775: }
776:
777: cv.visitVarInsn(ALOAD, 1);
778: cv.visitInsn(q.ignoreCache ? ICONST_1 : ICONST_0);
779: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setIgnoreCache",
780: "(Z)V");
781:
782: cv.visitVarInsn(ALOAD, 1);
783: cv.visitInsn(q.resultUnique ? ICONST_1 : ICONST_0);
784: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setUnique",
785: "(Z)V");
786:
787: cv.visitVarInsn(ALOAD, 1);
788: Util.visitLongConstant(cv, q.rangeFirst);
789: Util.visitLongConstant(cv, q.rangeLast);
790: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setRange",
791: "(JJ)V");
792:
793: if (q.ordering != null) {
794: cv.visitVarInsn(ALOAD, 1);
795: cv.visitLdcInsn(q.ordering);
796: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setOrdering",
797: "(Ljava/lang/String;)V");
798: }
799:
800: if (q.resultClass != null) {
801: cv.visitVarInsn(ALOAD, 1);
802: cv.visitLdcInsn(q.resultClass);
803: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN,
804: "setResultClass", "(Ljava/lang/String;)V");
805: }
806:
807: cv.visitVarInsn(ALOAD, 1);
808: cv.visitInsn(q.includeSubclasses ? ICONST_1 : ICONST_0);
809: cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN,
810: "setIncludeSubClasses", "(Z)V");
811:
812: //addNamedQuery("${nq.name}", sq);
813: cv.visitVarInsn(ALOAD, 0);
814: cv.visitLdcInsn(q.name);
815: cv.visitVarInsn(ALOAD, 1);
816: cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
817: "addNamedQuery", "(Ljava/lang/String;L" + sqJCN
818: + ";)V");
819: }
820: cv.visitInsn(RETURN);
821: cv.visitMaxs(0, 0);
822: }
823:
824: protected void generatePersonalityMethods(HomeContext gc) {
825: }
826:
827: public final static String getJVMClassName(String className) {
828: return StringReplace.replaceChar('.', '/', className);
829: }
830:
831: public final static String getJVMClassName(java.lang.Class clazz) {
832: return getJVMClassName(clazz.getName());
833: }
834:
835: public final static String getJVMType(java.lang.Class clazz) {
836: return getJVMType(clazz.getName());
837: }
838:
839: public final static String getJVMType(String className) {
840: return "L" + getJVMClassName(className) + ";";
841: }
842:
843: public final static String getJVMType(PType pt) {
844: return Type.getType(pt.getJavaClass()).getDescriptor();
845: }
846:
847: protected class HomeContext {
848: public final String classToWriteJCN;
849: public final String xHomeJCN;
850: public final String xHomeJT;
851: public final String xJCN;
852: public final String xJT;
853: public final String super ClassJCN;
854: public final SpeedoClass sc;
855: public final ClassVisitor cv;
856: public final Map ctx;
857: public final String[] userCacheNames;
858: public final Map ucn2sfs;
859: public final String classJT = "Ljava/lang/Class;";
860:
861: public HomeContext(SpeedoClass scl, ClassVisitor clav,
862: Map context) {
863: sc = scl;
864: cv = clav;
865: ctx = context;
866: xJCN = getJVMClassName(sc.getFQName());
867: xJT = getJVMType(xJCN);
868: xHomeJCN = getJVMClassName(NamingRules.homeName(sc
869: .getFQName()));
870: xHomeJT = getJVMType(xHomeJCN);
871: classToWriteJCN = xHomeJCN;
872: super ClassJCN = getJVMClassName(getSuperClass());
873: ucn2sfs = computeUserCaches(sc);
874: userCacheNames = (String[]) ucn2sfs.keySet().toArray(
875: new String[ucn2sfs.size()]);
876: }
877: }
878: }
|