Package org.objectweb.speedo.generation.generator.home

Source Code of org.objectweb.speedo.generation.generator.home.HomeGenerator

/**
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package org.objectweb.speedo.generation.generator.home;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.jorm.lib.JormPathHelper;
import org.objectweb.jorm.metainfo.api.Class;
import org.objectweb.jorm.metainfo.api.ClassRef;
import org.objectweb.jorm.metainfo.api.GenClassMapping;
import org.objectweb.jorm.metainfo.api.GenClassRef;
import org.objectweb.jorm.metainfo.api.MetaObject;
import org.objectweb.jorm.metainfo.api.NameDef;
import org.objectweb.jorm.metainfo.api.ReferenceMapping;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.generation.enhancer.common.Util;
import org.objectweb.speedo.generation.generator.lib.AbstractSpeedoGenerator;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.mapper.lib.Object2StringSerializer;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.metadata.SpeedoPredefinedQuery;
import org.objectweb.speedo.metadata.SpeedoXMLDescriptor;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.speedo.tools.StringReplace;

import java.io.FileOutputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
*
* @author S.Chassande-Barrioz
*/
public abstract class HomeGenerator extends AbstractSpeedoGenerator implements Constants {

    public final static String LOGGER_NAME = SpeedoProperties.LOGGER_NAME
            + ".generation.generator.homes";

    public final static String TEMPLATE_NAME = TEMPLATE_DIR + ".home.Home";
   
    /**
     * Provides the class to be inherited by the generated Home.
     * @return  The Java Class metaobject.
     */
    protected abstract java.lang.Class getSuperClass();
   
    /**
     * Provides the class to be used by the generated Home for query creation.
     * @return  The Java Class metaobject.
     */
    protected abstract java.lang.Class getQueryClass();

    public HomeGenerator(Personality p) {
      super(p);
    }
   
    // IMPLEMENTATION OF THE GeneratorComponent INTERFACE //
    //----------------------------------------------------//

    public boolean init() throws SpeedoException {
        logger = scp.loggerFactory.getLogger(LOGGER_NAME);
        return !scp.getXmldescriptor().isEmpty();
    }

    public void generate(SpeedoClass sClass, String fileName)
    throws SpeedoException {
       
        final ClassWriter cv = new ClassWriter(true);
        Map ctx = getContextAsMap(sClass);
        HomeContext gc = new HomeContext(sClass, cv, ctx);
        //create the class
        cv.visit(V1_1, ACC_PUBLIC + ACC_SUPER + ACC_ABSTRACT,
                gc.xHomeJCN,
                gc.superClassJCN,
                new String[]{}, gc.xHomeJCN);
        generateFinalStaticFields(gc);
        generateStaticClause(gc);
        generateClassMethod(gc);
        generatePersonalityMethods(gc);
        generateNoArgConstructor(gc);
        generateNewSpeedoPOInstance(gc);
        generateGetVersioningStrategy(gc);
        generateIsDetachable(gc);
        generateIsAbstract(gc);
        generateGetClassProperties(gc);
        generateWriteIntention(gc);
        generateActiveUserCache(gc);
        generateIniSHMethod(gc);
        cv.visitEnd();
       
        try {
            FileOutputStream fos = new FileOutputStream(fileName);
            fos.write(cv.toByteArray());
            fos.close();
        } catch (Exception e) {
            throw new SpeedoException("Problem while generating PAccessor.", e);
        }
    }

    private void getJormConfig(SpeedoClass sc, Properties classProperties)
            throws SpeedoException {
        //Build the map
        // Put the binder class name of the current persistent class
        String id = JormPathHelper.getPath(sc.jormclass);
        NameDef nd = getClassNameDef(sc.jormclass);
        jormConfigs(nd, sc, sc.jormclass, id, classProperties);

        //Put the binder class name for each reference field
        SpeedoXMLDescriptor xml = sc.moPackage.xmlDescriptor;
        for (Iterator it = sc.jormclass.getAllFields().iterator(); it
                .hasNext();) {
            Object o = it.next();
            if (o instanceof ClassRef) {
                nd = getRefNameDef((ClassRef) o, sc.jormclass);
                id = JormPathHelper.getPath(((ClassRef) o));
                SpeedoClass tsc = xml.getSpeedoClass(((ClassRef) o)
                        .getMOClass().getFQName(), true);
                jormConfigs(nd, tsc, sc.jormclass, id, classProperties);
            } else if (o instanceof GenClassRef) {
                GenClassRef gcr = (GenClassRef) o;
                nd = getRefNameDef(gcr, sc.jormclass);
                id = JormPathHelper.getPath((GenClassRef) o, false);
                jormConfigs(nd, sc, gcr, id, classProperties);
                while (gcr.isGenClassRef()) {
                    gcr = gcr.getGenClassRef();
                    nd = getElemNameDef(gcr, sc.jormclass);
                    id = JormPathHelper.getPath(gcr, false);
                    jormConfigs(nd, sc, gcr, id, classProperties);
                }
                if (gcr.isClassRef()) {
                    ClassRef cr = gcr.getClassRef();
                    nd = getElemNameDef(gcr, sc.jormclass);
                    id = JormPathHelper.getPath(cr);
                    SpeedoClass tsc = xml.getSpeedoClass(cr.getMOClass()
                            .getFQName(), true);
                    jormConfigs(nd, tsc, cr, id, classProperties);
                }
            }
        }
    }

    private void jormConfigs(NameDef nd, SpeedoClass targetClass,
            MetaObject sourceMO, String key, Properties jormProp)
            throws SpeedoException {
        scp.nmf.getNamingManager(targetClass).getJormNamingConfig(nd,
                targetClass, sourceMO, key, jormProp);
    }

    private GenClassMapping getGenClassMapping(GenClassRef gcr, Class clazz)
            throws SpeedoException {
        String gcid = gcr.getGenClassId();
        GenClassMapping gcm = getMapping(clazz).getGenClassMapping(gcid);
        if (gcm == null) {
            Class klass = clazz;
            Collection superclasses = klass.getSuperClasses();
            while (gcm == null && !superclasses.isEmpty()) {
                klass = (Class) superclasses.iterator().next();
                gcm = getMapping(klass).getGenClassMapping(gcid);
                superclasses = klass.getSuperClasses();
            }
        }
        if (gcm == null) {
            throw new SpeedoException("No GenClassMapping found for the field "
                    + gcid);
        }
        return gcm;
    }

    private NameDef getRefNameDef(GenClassRef gcr, Class clazz)
            throws SpeedoException {
        return (NameDef) getGenClassMapping(gcr, clazz).getIdentifierMapping()
                .getLinkedMO();
    }

    private NameDef getElemNameDef(GenClassRef gcr, Class clazz)
            throws SpeedoException {
        return (NameDef) getGenClassMapping(gcr, clazz).getReferenceMapping()
                .getLinkedMO();
    }

    private ReferenceMapping getReferenceMapping(ClassRef cr, Class clazz)
            throws SpeedoException {
        String rid = cr.getName();
        ReferenceMapping rm = getMapping(clazz).getClassMapping()
                .getReferenceMapping(rid);
        if (rm == null) {
            Class klass = clazz;
            Collection superclasses = klass.getSuperClasses();
            while (rm == null && !superclasses.isEmpty()) {
                klass = (Class) superclasses.iterator().next();
                rm = getMapping(klass).getClassMapping().getReferenceMapping(
                        rid);
                superclasses = klass.getSuperClasses();
            }
        }
        if (rm == null) {
            throw new SpeedoException(
                    "No ReferenceMapping found for the field " + rid);
        }
        return rm;

    }

    private NameDef getRefNameDef(ClassRef cr, Class clazz)
            throws SpeedoException {
        return (NameDef) getReferenceMapping(cr, clazz).getLinkedMO();
    }

   
   
    private void generateFinalStaticFields(HomeContext gc) {
        //protected static final byte VERSIONING_STRATEGY = ${versioningStrategy.byteValue()};
        gc.cv.visitField(ACC_PROTECTED + ACC_FINAL + ACC_STATIC,
                "VERSIONING_STRATEGY", "B", gc.ctx.get("versioningStrategy"), null);
       
        //public static final boolean DETACHABLE = $detachable;
        gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "DETACHABLE", "Z",
                new Integer(gc.sc.isDetachable ? 1 : 0), null);
       
        //public static final String[] FIELD_NAMES = ${fieldsNamesArray};
        gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_NAMES", "[Ljava/lang/String;", null, null);
        //public static final Class[] FIELD_TYPES = ${fieldsTypesArray};
        gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_TYPES", "[Ljava/lang/Class;", null, null);
        //public static final byte[] FIELD_FLAGS = new byte[0];
        gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIELD_FLAGS", "[B", null, null);
        //public static final Class SUPER_CLASS = #if($hasSuperclass)#**#${superClassName}.class#else#**#null#end#**#;
        gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "SUPER_CLASS", "Ljava/lang/Class;", null, null);

        for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
            gc.cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
                    gc.userCacheNames[ucIdx] + "_USER_CACHE_ID",
                    "I", new Integer(ucIdx), null);
        }
    }
    private void generateStaticClause(HomeContext gc) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
        final HashSet staticfieldNames = new HashSet();
        generateFieldNamesInit(gc, cv);
        generateFieldTypesInit(gc, staticfieldNames, cv);

        // Field flags
        cv.visitInsn(ICONST_0);
        cv.visitIntInsn(NEWARRAY, T_BYTE);
        cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_FLAGS", "[B");
       
        //Super class
        if (gc.sc.getSuperClassName() == null) {
            cv.visitInsn(ACONST_NULL);
        } else {
            generateDotClass(gc.sc.getSuperClassName(), gc, staticfieldNames, cv);
        }
        cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "SUPER_CLASS", "Ljava/lang/Class;");
       
        cv.visitInsn(RETURN);
        cv.visitMaxs(0, 0);

        for (Iterator iter = staticfieldNames.iterator(); iter.hasNext();) {
            String fn = (String) iter.next();
            gc.cv.visitField(ACC_STATIC + ACC_SYNTHETIC, fn, gc.classJT, null, null);
        }
    }
    private void generateFieldNamesInit(HomeContext gc, CodeVisitor cv) {
        Collection fields = gc.sc.fields.values();
        cv.visitIntInsn(BIPUSH, fields.size());
        cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
        int idx = 0;
        for(Iterator it = fields.iterator(); it.hasNext();) {
            SpeedoField sf = (SpeedoField) it.next();
            cv.visitInsn(DUP);
            Util.visitIntConstant(cv, idx);
            cv.visitLdcInsn(sf.name);
            cv.visitInsn(AASTORE);
            idx ++;
        }
        cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_NAMES", "[Ljava/lang/String;");
    }
    private void generateFieldTypesInit(HomeContext gc, final HashSet staticfieldNames, CodeVisitor cv) {
        Collection fields = gc.sc.fields.values();
        cv.visitIntInsn(BIPUSH, fields.size());
        cv.visitTypeInsn(ANEWARRAY, "java/lang/Class");
       
        final String fieldType = "TYPE";
        int idx = 0;
        for(Iterator it = fields.iterator(); it.hasNext();) {
            cv.visitInsn(DUP);
            Util.visitIntConstant(cv, idx);
            idx ++;
            SpeedoField sf = (SpeedoField) it.next();
            Type t = Type.getType(sf.type);
            switch (t.getSort()) {
            case Type.BOOLEAN:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", fieldType, gc.classJT);
                break;
            case Type.BYTE:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Byte", fieldType, gc.classJT);
                break;
            case Type.CHAR:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Character", fieldType, gc.classJT);
                break;
            case Type.DOUBLE:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Double", fieldType, gc.classJT);
                break;
            case Type.FLOAT:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Float", fieldType, gc.classJT);
                break;
            case Type.INT:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Integer", fieldType, gc.classJT);
                break;
            case Type.LONG:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Long", fieldType, gc.classJT);
                break;
            case Type.SHORT:
                cv.visitFieldInsn(GETSTATIC, "java/lang/Short", fieldType, gc.classJT);
                break;
            case Type.ARRAY:
                String cn ;
                switch (t.getElementType().getSort()) {
                case Type.BOOLEAN:
                case Type.BYTE:
                case Type.CHAR:
                case Type.DOUBLE:
                case Type.FLOAT:
                case Type.INT:
                case Type.LONG:
                case Type.SHORT:
                    cn = t.getDescriptor();
                    break;
                default:
                    cn = t.getElementType().getClassName();
                    break;
                }
                generateDotClass(cn, gc, staticfieldNames, cv);
                break;
            default:
                generateDotClass(t.getClassName(), gc, staticfieldNames, cv);
                break;
            }
            cv.visitInsn(AASTORE);
        }
        cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, "FIELD_TYPES", "[Ljava/lang/Class;");
    }
    private void generateDotClass(final String className,
            final HomeContext gc,
            final HashSet staticfieldNames ,
            final CodeVisitor cv) {
        final String staticFieldName = "class$"
            + StringReplace.replaceString("[", "array$", className)
            .replace('.', '$');
        cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
        staticfieldNames.add(staticFieldName);
        //this type has not been already met
        Label labelElse = new Label();
        Label labelEnd = new Label();
        cv.visitJumpInsn(IFNONNULL, labelElse);
        {
            cv.visitLdcInsn(className);
            cv.visitMethodInsn(INVOKESTATIC, gc.classToWriteJCN, "class$", "(Ljava/lang/String;)" + gc.classJT);
            cv.visitInsn(DUP);
            cv.visitFieldInsn(PUTSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
            cv.visitJumpInsn(GOTO, labelEnd);
        }
        cv.visitLabel(labelElse);
        {
            cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, staticFieldName, gc.classJT);
        }
        cv.visitLabel(labelEnd);
    }
    private void generateClassMethod(HomeContext gc) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_STATIC + ACC_SYNTHETIC, "class$",
                "(Ljava/lang/String;)Ljava/lang/Class;", null, null);
        Label labelTry = new Label();
        cv.visitLabel(labelTry);
        cv.visitVarInsn(ALOAD, 0);
        cv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName",
                "(Ljava/lang/String;)Ljava/lang/Class;");
        Label labelEndTry = new Label();
        cv.visitLabel(labelEndTry);
        cv.visitInsn(ARETURN);
        Label labelCatch = new Label();
        cv.visitLabel(labelCatch);
        cv.visitVarInsn(ASTORE, 1);
        cv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
        cv.visitInsn(DUP);
        cv.visitVarInsn(ALOAD, 1);
        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException",
                "getMessage", "()Ljava/lang/String;");
        cv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError",
                "<init>", "(Ljava/lang/String;)V");
        cv.visitInsn(ATHROW);
        cv.visitTryCatchBlock(labelTry, labelEndTry, labelCatch, "java/lang/ClassNotFoundException");
        cv.visitMaxs(0, 0);
    }
    protected void generateNoArgConstructor(HomeContext gc) {
        CodeVisitor mv = gc.cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, gc.superClassJCN, "<init>", "()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
    private void generateNewSpeedoPOInstance(HomeContext gc) {
        //protected PersistentObjectItf newSpeedoPOInstance(Class clazz) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_PROTECTED, "newSpeedoPOInstance",
                "(Ljava/lang/Class;)Lorg/objectweb/speedo/mim/api/PersistentObjectItf;", null, null);
        if (gc.sc.isAbstract) {
            cv.visitInsn(ACONST_NULL);
            cv.visitInsn(ARETURN);
        } else {
            Label l0 = new Label();
            cv.visitLabel(l0);
            cv.visitTypeInsn(NEW, gc.xJCN);
            cv.visitInsn(DUP);
            cv.visitMethodInsn(INVOKESPECIAL, gc.xJCN, "<init>", "()V");
//            cv.visitVarInsn(ASTORE, 2);
//            cv.visitVarInsn(ALOAD, 2);
            cv.visitTypeInsn(CHECKCAST, "org/objectweb/speedo/mim/api/PersistentObjectItf");
            Label l1 = new Label();
            cv.visitLabel(l1);
            cv.visitInsn(ARETURN);
            Label l2 = new Label();
            cv.visitLabel(l2);
            cv.visitVarInsn(ASTORE, 2);
            cv.visitTypeInsn(NEW, personality.getUserRuntimeExceptionClassNameSlash());
            cv.visitInsn(DUP);
            cv.visitLdcInsn("Impossible to instanciate the class " + gc.classToWriteJCN + ": ");
            cv.visitVarInsn(ALOAD, 2);
            cv.visitMethodInsn(INVOKESPECIAL,
                personality.getUserRuntimeExceptionClassNameSlash(),
                    "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
            cv.visitInsn(ATHROW);
            cv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
        }
        cv.visitMaxs(0, 0);
    }
    private void generateGetVersioningStrategy(HomeContext gc) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
                "getVersioningStrategy", "()B", null, null);
        cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, "VERSIONING_STRATEGY", "B");
        cv.visitInsn(IRETURN);
        cv.visitMaxs(1, 1);
    }
    private void generateIsDetachable(HomeContext gc) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
                "isDetachable", "()Z", null, null);
        cv.visitFieldInsn(GETSTATIC, gc.classToWriteJCN, "DETACHABLE", "Z");
        cv.visitInsn(IRETURN);
        cv.visitMaxs(1, 1);
    }
    private void generateIsAbstract(HomeContext gc) {
        if (gc.sc.isAbstract) {
            CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL,
                    "isAbstract", "()Z", null, null);
            cv.visitInsn(ICONST_1);
            cv.visitInsn(IRETURN);
            cv.visitMaxs(1, 1);
        }
    }
    private void generateGetClassProperties(HomeContext gc) throws SpeedoException {
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC + ACC_FINAL, "getClassProperties",
                "()Ljava/util/Properties;", null, null);
        cv.visitTypeInsn(NEW, "java/util/Properties");
        cv.visitInsn(DUP);
        cv.visitMethodInsn(INVOKESPECIAL, "java/util/Properties", "<init>", "()V");
        cv.visitVarInsn(ASTORE, 1);
       
        Properties classProperties = new Properties();
        getJormConfig(gc.sc, classProperties);
        String xmlFileName = gc.sc.moPackage.xmlDescriptor.xmlFile;
        xmlFileName = StringReplace.replaceChar('/', '.', xmlFileName);
        xmlFileName = StringReplace.replaceChar(fs, '.', xmlFileName);
        classProperties.setProperty(
                Object2StringSerializer.DESC_FILE_NAME_PROP,
                xmlFileName);
        for (Iterator it = classProperties.entrySet().iterator(); it.hasNext();) {
            Map.Entry me = (Map.Entry) it.next();
            cv.visitVarInsn(ALOAD, 1);
            cv.visitLdcInsn(me.getKey());
            cv.visitLdcInsn(me.getValue());
            cv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Properties", "setProperty",
                    "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;");
            cv.visitInsn(POP); //remove the result of the setProperty method
        }
       
        cv.visitVarInsn(ALOAD, 1);
        cv.visitInsn(ARETURN);
        cv.visitMaxs(3, 2);
    }
    private void generateWriteIntention(HomeContext gc) {
        if (gc.userCacheNames.length == 0) {
            return;
        }
        //public StateItf writeIntention(PersistentObjectItf sp, long[] fields, Object thinLock)
        final String methodDesc = "("
            + getJVMType(PersistentObjectItf.class)
            + "[J"
            + getJVMType(Object.class)
            + ")" + getJVMType(StateItf.class);
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "writeIntention",
                methodDesc, null, null);
        //StateItf sa = super.writeIntention(sp, fields, thinLock);
        cv.visitVarInsn(ALOAD, 0);
        cv.visitVarInsn(ALOAD, 1);
        cv.visitVarInsn(ALOAD, 2);
        cv.visitVarInsn(ALOAD, 3);
        cv.visitMethodInsn(INVOKESPECIAL, gc.superClassJCN, "writeIntention", methodDesc);
        cv.visitVarInsn(ASTORE, 4);

        //if (fields == null) {
        cv.visitVarInsn(ALOAD, 2);
        Label labelElse = new Label();
        cv.visitJumpInsn(IFNONNULL, labelElse);
        Label labelEnd = new Label();
        {
            //sa.indexFieldModified(0xffffffff, false);
            cv.visitVarInsn(ALOAD, 4);
            cv.visitLdcInsn(new Integer(0xffffffff));
            cv.visitInsn(ICONST_0);
            cv.visitMethodInsn(INVOKEINTERFACE,
                    getJVMClassName(StateItf.class),
                    "indexFieldModified", "(IZ)V");
            cv.visitJumpInsn(GOTO, labelEnd);
        }
        cv.visitLabel(labelElse);
        {
            for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
                String ucn = gc.userCacheNames[ucIdx];
                List fields = (List) gc.ucn2sfs.get(ucn);
                for(Iterator itf = fields.iterator(); itf.hasNext();) {
                    SpeedoField sf = (SpeedoField) itf.next();
                    //if ((fields[${f.jormFieldIdLongPos}] & ${f.jormFieldId}L) != 0) {
                    cv.visitVarInsn(ALOAD, 2);
                    Util.visitIntConstant(cv, sf.number / 64);
                    cv.visitInsn(LALOAD);
                    Util.visitLongConstant(cv, 1L << (sf.number % 64));
                    cv.visitInsn(LAND);
                    cv.visitInsn(LCONST_0);
                    cv.visitInsn(LCMP);
                    Label labelNext = new Label();
                    cv.visitJumpInsn(IFEQ, labelNext);
                    {
                        //sa.indexFieldModified(${ucn}_USER_CACHE_ID, false);
                        cv.visitVarInsn(ALOAD, 4);
                        Util.visitIntConstant(cv, ucIdx);
                        cv.visitInsn(ICONST_0);
                        cv.visitMethodInsn(INVOKEINTERFACE,
                                getJVMClassName(StateItf.class),
                                "indexFieldModified", "(IZ)V");
                    }
                    cv.visitLabel(labelNext);
                }
            }
        }
        cv.visitLabel(labelEnd);
        //return sa;
        cv.visitVarInsn(ALOAD, 4);
        cv.visitInsn(ARETURN);
        cv.visitMaxs(0, 0);
    }
    private void generateActiveUserCache(HomeContext gc) {
        if (gc.userCacheNames.length == 0) {
            return;
        }
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "activeUserCache",
                "(Ljava/lang/String;)Z", null, null);

        //if (cacheName == null) {
        cv.visitVarInsn(ALOAD, 1);
        Label l0 = new Label();
        cv.visitJumpInsn(IFNONNULL, l0);
        {
            //return false;
            cv.visitInsn(ICONST_0);
            cv.visitInsn(IRETURN);
        }
        cv.visitLabel(l0);
        //} else if ("*".equals(cacheName)) {
        cv.visitLdcInsn("*");
        cv.visitVarInsn(ALOAD, 1);
        cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
        Label labelElse = new Label();
        cv.visitJumpInsn(IFEQ, labelElse);
        {
            //foreach($ucn in $userCacheNames)
            for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
                //activeUserCache("$ucn");
                cv.visitVarInsn(ALOAD, 0);
                cv.visitLdcInsn(gc.userCacheNames[ucIdx]);
                cv.visitMethodInsn(INVOKEVIRTUAL,
                        gc.classToWriteJCN,
                        "activeUserCache", "(Ljava/lang/String;)Z");
                cv.visitInsn(POP);
            }
            //return true;
            cv.visitInsn(ICONST_1);
            cv.visitInsn(IRETURN);
        }
        cv.visitLabel(labelElse);
        for (int ucIdx = 0; ucIdx < gc.userCacheNames.length; ucIdx++) {
            final String ucn = gc.userCacheNames[ucIdx];
            //} else if ("${ucn}".equals(cacheName)) {
            cv.visitLdcInsn(ucn);
            cv.visitVarInsn(ALOAD, 1);
            cv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
            Label labelNext = new Label();
            cv.visitJumpInsn(IFEQ, labelNext);
            {
                //this.addUserCache(cacheName, ${userCacheFieldNames.get($ucn)}, ${ucn}_USER_CACHE_ID);
                cv.visitVarInsn(ALOAD, 0); //this
                cv.visitVarInsn(ALOAD, 1); //cacheName parameter
               
                //parameter ${userCacheFieldNames.get($ucn)}
                // new String[]{"f1", "f2"}
                final List fields = (List) gc.ucn2sfs.get(ucn);
                Util.visitIntConstant(cv, fields.size()); //Array size
                cv.visitTypeInsn(ANEWARRAY, "java/lang/String");
                for (int fieldIdx = 0; fieldIdx < fields.size(); fieldIdx++) {
                    SpeedoField sf = (SpeedoField) fields.get(fieldIdx);
                    cv.visitInsn(DUP);
                    Util.visitIntConstant(cv, fieldIdx); //index
                    cv.visitLdcInsn(sf.name); //value = field name
                    cv.visitInsn(AASTORE);
                }
               
                Util.visitIntConstant(cv, ucIdx); //${ucn}_USER_CACHE_ID
                cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
                        "addUserCache", "(Ljava/lang/String;[Ljava/lang/String;I)Lorg/objectweb/speedo/usercache/api/UserCache;");
                cv.visitInsn(POP);
                //return true;
                cv.visitInsn(ICONST_1);
                cv.visitInsn(IRETURN);
            }
            cv.visitLabel(labelNext);
        }
        //return false;
        cv.visitInsn(ICONST_0);
        cv.visitInsn(IRETURN);
        cv.visitMaxs(0, 0);
    }
    private void generateIniSHMethod(HomeContext gc) {
        CodeVisitor cv = gc.cv.visitMethod(ACC_PUBLIC, "initSH", "()V", null, null);
        String sqJCN = getJVMClassName(getQueryClass());
        for (Iterator it = gc.sc.name2query.values().iterator(); it.hasNext();) {
            SpeedoPredefinedQuery q = (SpeedoPredefinedQuery) it.next();
            //sq = new SpeedoQuery();
            cv.visitTypeInsn(NEW, sqJCN);
            cv.visitInsn(DUP);
            cv.visitMethodInsn(INVOKESPECIAL, sqJCN, "<init>", "()V");
            cv.visitVarInsn(ASTORE, 1); //Always use the same variable 1
           
            if (q.query != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.query);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "defineWith", "(Ljava/lang/String;)V");
            }
            if (q.filter != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.filter);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setFilter", "(Ljava/lang/String;)V");
            }
            if (q.declareImports != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.declareImports);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareImports", "(Ljava/lang/String;)V");
            }
            if (q.declareParameters != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.declareParameters);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareParameters", "(Ljava/lang/String;)V");
            }
            if (q.declareVariables != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.declareVariables);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "declareVariables", "(Ljava/lang/String;)V");
            }

            cv.visitVarInsn(ALOAD, 1);
            cv.visitInsn(q.ignoreCache ? ICONST_1 : ICONST_0);
            cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setIgnoreCache", "(Z)V");

            cv.visitVarInsn(ALOAD, 1);
            cv.visitInsn(q.resultUnique ? ICONST_1 : ICONST_0);
            cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setUnique", "(Z)V");

            cv.visitVarInsn(ALOAD, 1);
            Util.visitLongConstant(cv, q.rangeFirst);
            Util.visitLongConstant(cv, q.rangeLast);
            cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setRange", "(JJ)V");
           
            if (q.ordering != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.ordering);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setOrdering", "(Ljava/lang/String;)V");
            }
           
            if (q.resultClass != null) {
                cv.visitVarInsn(ALOAD, 1);
                cv.visitLdcInsn(q.resultClass);
                cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setResultClass", "(Ljava/lang/String;)V");
            }
           
            cv.visitVarInsn(ALOAD, 1);
            cv.visitInsn(q.includeSubclasses ? ICONST_1 : ICONST_0);
            cv.visitMethodInsn(INVOKEVIRTUAL, sqJCN, "setIncludeSubClasses", "(Z)V");
           
            //addNamedQuery("${nq.name}", sq);
            cv.visitVarInsn(ALOAD, 0);
            cv.visitLdcInsn(q.name);
            cv.visitVarInsn(ALOAD, 1);
            cv.visitMethodInsn(INVOKEVIRTUAL, gc.classToWriteJCN,
                    "addNamedQuery", "(Ljava/lang/String;L" + sqJCN + ";)V");
        }
        cv.visitInsn(RETURN);
        cv.visitMaxs(0, 0);
    }
    protected void generatePersonalityMethods(HomeContext gc) {
    }
    public final static String getJVMClassName(String className) {
        return StringReplace.replaceChar('.', '/', className);
    }
    public final static String getJVMClassName(java.lang.Class clazz) {
        return getJVMClassName(clazz.getName());
    }
    public final static String getJVMType(java.lang.Class clazz) {
        return getJVMType(clazz.getName());
    }
    public final static String getJVMType(String className) {
        return "L" + getJVMClassName(className) + ";";
    }
    public final static String getJVMType(PType pt) {
        return Type.getType(pt.getJavaClass()).getDescriptor();
    }
    protected class HomeContext {
        public final String classToWriteJCN;
        public final String xHomeJCN;
        public final String xHomeJT;
        public final String xJCN;
        public final String xJT;
        public final String superClassJCN;
        public final SpeedoClass sc;
        public final ClassVisitor cv;
        public final Map ctx;
        public final String[] userCacheNames;
        public final Map ucn2sfs;
        public final String classJT = "Ljava/lang/Class;";

        public HomeContext(SpeedoClass scl, ClassVisitor clav, Map context) {
            sc = scl;
            cv = clav;
            ctx = context;
            xJCN = getJVMClassName(sc.getFQName());
            xJT = getJVMType(xJCN);
            xHomeJCN = getJVMClassName(NamingRules.homeName(sc.getFQName()));
            xHomeJT = getJVMType(xHomeJCN);
            classToWriteJCN = xHomeJCN;
            superClassJCN = getJVMClassName(getSuperClass());
            ucn2sfs = computeUserCaches(sc);
            userCacheNames = (String[]) ucn2sfs.keySet().toArray(
                    new String[ucn2sfs.size()]);
        }
    }
}
TOP

Related Classes of org.objectweb.speedo.generation.generator.home.HomeGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.