Package org.objectweb.speedo.generation.jorm

Source Code of org.objectweb.speedo.generation.jorm.JormMIBuilder

/**
* 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.jorm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.objectweb.asm.Type;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.metainfo.api.Class;
import org.objectweb.jorm.metainfo.api.ClassMapping;
import org.objectweb.jorm.metainfo.api.ClassProject;
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.IdentifierMapping;
import org.objectweb.jorm.metainfo.api.Manager;
import org.objectweb.jorm.metainfo.api.Mapping;
import org.objectweb.jorm.metainfo.api.MetaObject;
import org.objectweb.jorm.metainfo.api.NameDef;
import org.objectweb.jorm.metainfo.api.PrimitiveElement;
import org.objectweb.jorm.metainfo.api.Reference;
import org.objectweb.jorm.metainfo.api.ReferenceMapping;
import org.objectweb.jorm.metainfo.api.ScalarField;
import org.objectweb.jorm.metainfo.api.TypedElement;
import org.objectweb.jorm.metainfo.lib.MetaInfoPrinter;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.jorm.type.api.PTypeSpace;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoProperties;
import org.objectweb.speedo.api.UserFieldMapping;
import org.objectweb.speedo.generation.generator.lib.AbstractSpeedoGenerator;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoCollection;
import org.objectweb.speedo.metadata.SpeedoDiscriminator;
import org.objectweb.speedo.metadata.SpeedoElement;
import org.objectweb.speedo.metadata.SpeedoExtension;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.metadata.SpeedoInheritedField;
import org.objectweb.speedo.metadata.SpeedoMap;
import org.objectweb.speedo.metadata.SpeedoNoFieldColumn;
import org.objectweb.speedo.naming.api.MIBuilderHelper;
import org.objectweb.speedo.naming.lib.NamingManagerFactory;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Loggable;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;

/**
* This class is a builder of jorm meta information. Its entries are the
* following:
* <UL>
* <LI>the jorm meta information manager,</LI>
* <LI>A collection of SpeedoClass object,</LI>
* <LI>the project name,</LI>
* <LI>the mapper name,</LI>
* <LI>a JormMIMappingBuilder instance able to build the mapping part for the
* mapper which the name is specified.</LI>
* </UL>
* @author S.Chassande-Barrioz
*/
public class JormMIBuilder implements MIBuilderHelper, Loggable {

    /**
     * is the prefix of the fields used to identify a generic class
     */
    public final static String GENCLASS_ID_PREFIX = "id_";

    /**
     * is the prefix of the fields used for the element of a generic class
     */
    public final static String GENCLASS_ELM_PREFIX = "elem_";

    public final static String DEFAULT_RDB_BUILDER
            = "org.objectweb.speedo.generation.jorm.rdb.RdbJORMMapping";

    /**
     * is the name of the index field in the list (Genclass).
     */
    public final static String LIST_INDEX = "idx";
    public final static String MAP_INDEX = "idx";

    /**
     * is the jorm meta information manager iinside which the Class and the
     * composite name must be defined.
     */
    private Manager manager = null;
    private NamingManagerFactory nmf;

    private Logger logger = null;
    private LoggerFactory loggerFactory = null;
  private boolean debug = false;

    /**
     * Builds a JormMIBuilder without a jorm meta information manager
     * and a logger.
     */
    public JormMIBuilder() {
    }

    /**
     * Builds a JormMIBuilder with a jorm meta information manager and a logger
     * @param manager
     */
    public JormMIBuilder(Manager manager, Logger logger) {
        this.manager = manager;
        this.logger = logger;
    }

    /**
     * Builds a JormMIBuilder with a jorm meta information manager and a logger
     * @param manager
     */
    public JormMIBuilder(Manager manager, NamingManagerFactory nmf, Logger logger) {
        this.manager = manager;
        this.logger = logger;
        this.nmf = nmf;
    }

    /**
     * retrieves the jorm meta information manager hosting the Class and
     * CompositeName instances.
     */
    public Manager getManager() {
        return manager;
    }

    /**
     * retrieves the jorm meta information manager hosting the Class and
     * CompositeName instances.
     */
    public void setManager(Manager manager) {
        this.manager = manager;
    }

    public Logger getLogger() {
        return logger;
    }

    public void setLogger(Logger logger) {
        this.logger = logger;
    }

    public void setLoggerFactory(LoggerFactory lf) {
        this.loggerFactory = lf;
    }

    public LoggerFactory getLoggerFactory() {
        return loggerFactory;
    }
    /**
     * Creates the jorm meta information for a set of persistent classes. Only
     * the generic part will be created.
     *
     * @param scs is a list of SpeedoClass instances.
     * @return a Collection of jorm meta object composed by Class instances and
     * CompositeName instances.
     */
    public Collection createMI(List scs) throws SpeedoException, PException {
        return createMI(scs, null, null);
    }

    /**
     * Creates the jorm meta information for a set of persistent classes.
     * @param scs is a list of SpeedoClass instances.
     * @param projectName is the project name for which the mapping must
     * be defined. If the value is null no mapping will be generated.
     * @param mapperName is the mapper name for which the mapping must
     * be defined. If the value is null no mapping will be generated.
     * @return a Collection of jorm meta object composed by Class instances and
     * CompositeName instances.
     */
    public Collection createMI(List scs,
                               String projectName,
                               String mapperName)
            throws SpeedoException, PException {
        JormMIMappingBuilder jmimb = null;
        String buildercn;
        if (mapperName != null) {
            if (mapperName.startsWith("rdb")) {
                buildercn = DEFAULT_RDB_BUILDER;
            } else {
                throw new SpeedoException(
                        "No default JormMIMappingBuilder for the mapper "
                        + mapperName);
            }
            try {
                jmimb = (JormMIMappingBuilder)
                        java.lang.Class.forName(buildercn).newInstance();
            } catch (Exception e) {
                throw new SpeedoException("Impossible to instanciate a the class "
                        + buildercn);
            }
            if (jmimb instanceof Loggable) {
                ((Loggable) jmimb).setLogger(logger);
            }
        }
        return createMI(scs, projectName, mapperName, jmimb);
    }
    /**
     * Creates the jorm meta information for a set of persistent classes.
     * @param scs is a list of SpeedoClass instances.
     * @param projectName is the project name for which the mapping must
     * be defined
     * @param mapperName is the mapper name for which the mapping must
     * be defined
     * @param mb is the build of the mapping part of the meta information
     * @return a Collection of jorm meta object composed by Class instances and
     * CompositeName instances.
     */
    public Collection createMI(List scs,
                               String projectName,
                               String mapperName,
                               JormMIMappingBuilder mb)
            throws SpeedoException, PException {
      if (manager == null) {
            throw new SpeedoException(
                    "the Jorm meta information manager must be assigned");
        }
      int size = scs.size();
      debug = logger.isLoggable(BasicLevel.DEBUG);
        ArrayList createdMOs = new ArrayList(size * 2);
        SpeedoClass sc;
        String mn;
        if (mapperName != null) {
            // take the mapper name without the sub mapper name
            int idx = mapperName.indexOf(".");
            mn = (idx != -1 ? mapperName.substring(0, idx) : mapperName);
        } else {
            mn = null;
        }

      //Order the list in according to the inheritance order
        orderMOsByInheritance(scs);
        // Create Class meta objects
      for(int i=0; i<size; i++) {
            sc = (SpeedoClass) scs.get(i);
             createJormClass(sc, projectName, mn, mb, createdMOs);
        }
      // Fill the meta information with primitive fields
        for(int i=0; i<size; i++) {
          sc = (SpeedoClass) scs.get(i);
             createPrimitiveFields(sc, projectName, mn, mb);
        }
      // Define the identifier of classes (list with the inheritance order)
      for(int i=0; i<size; i++) {
        sc = (SpeedoClass) scs.get(i);
        createIdentifierNameDef(sc, projectName, mn, mb, createdMOs);
      }
      // Fill the meta information with reference fields
        for(int i=0; i<size; i++) {
            sc = (SpeedoClass) scs.get(i);
            createReferences(sc, projectName, mn, mb, createdMOs);
        }
      //define the mapping of inherited field (list with the inheritance order)
      for(int i=0; i<size; i++) {
        sc = (SpeedoClass) scs.get(i);
        mapInheritance(sc, projectName, mn, mb);
      }


        if (logger.isLoggable(BasicLevel.DEBUG)) {
            MetaInfoPrinter mip = new MetaInfoPrinter(manager);
            for(int i=0; i<createdMOs.size(); i++) {
                mip.print("", (MetaObject) createdMOs.get(i), logger);
            }
        }
        return createdMOs;
    }

    /**
     * Orders the list of SpeedoClass instance according to the inheritance.
     * Firstly the ancestor class after its children.
     * @param scs is a list of Speedo which has to be ordered.
     */
    private void orderMOsByInheritance(List scs) {
        List newscs = new ArrayList(scs.size());
        if (debug) {
            logger.log(BasicLevel.DEBUG, "before ordering scs.size()=" + scs.size());
        }
        SpeedoClass sc;
        for(int i = 0; i<scs.size();) {
            sc = (SpeedoClass) scs.get(i);
            if (sc.getSuperClassName() == null) {
                //Add classes without parent
                scs.remove(i);
                newscs.add(sc);
                if (debug) {
                    logger.log(BasicLevel.DEBUG, "Class '" + sc.getFQName()
                        + "' has no parent");
                }
            } else {
                i++;
            }
        }
        int idx = 0;
        while (!scs.isEmpty() && idx < newscs.size()) {
            //Take an element in the new list
            sc = (SpeedoClass) newscs.get(idx);
            if (debug) {
                logger.log(BasicLevel.DEBUG, "Find children of the class '" + sc.getFQName() + "'.");
            }
            //Search its children in the old list
            for(int i = 0; i<scs.size();) {
                SpeedoClass child = (SpeedoClass) scs.get(i);
                if (child.getSuper() == sc) {
                    //It is a child
                    scs.remove(i);
                    newscs.add(child);
                    if (debug) {
                        logger.log(BasicLevel.DEBUG, "Class '"
                            + child.getFQName() + "' is a child of the class '"
                            + sc.getFQName() + "'.");
                    }
                } else {
                    i++;
                }
            }
            idx ++;
        }
        if (debug) {
            logger.log(BasicLevel.DEBUG, "newscs.size()=" + newscs.size());
        }
        scs.clear();
        scs.addAll(newscs);
    }
   
    /**
     * Creates the jorm meta information for a persistent class. Only the
     * primitive fields are defined in the meta information. To define the
     * references of a persistent object the 'createReferences' method must be
     * used.
     * @param sc is the Speedo meta object describing the class which the jorm
     * meta information must be built.
     * @param projectName is the project name for which the mapping must
     * be defined
     * @param mapperName is the mapper name for which the mapping must
     * be defined
     * @param mb is the build of the mapping part of the meta information
     * @param createdMOs is a result paramter. This collection must be fill with
     * the created Jorm Meta objects representing  a class or a composite name.
     * Here the meta object of the class will be added. In addition if the name
     * def of the class is based on a composite name then its meta object will
     * be added too.
     */
    private void createJormClass(SpeedoClass sc,
                            String projectName,
                            String mapperName,
                            JormMIMappingBuilder mb,
                            Collection createdMOs)
            throws SpeedoException, PException {
        Class clazz = manager.getClass(sc.getFQName());
        if (clazz == null) {
            clazz = manager.createClass(sc.getFQName());
            createdMOs.add(clazz);
        }
    if (sc.getSuperClassName() != null) {
      SpeedoClass parent = sc.getSpeedoClassFromContext(sc.getSuperClassName());
      if (parent == null) {
        throw new SpeedoException("No super class '"
            + sc.getSuperClassName() + "'found in the .jdo file: "
            + sc.getXMLFileName());
      }
      Class parentClazz = manager.getClass(parent.getFQName());
      if (parentClazz == null) {
        throw new SpeedoException("Internal algorythm problem: parent class must be treated before sub classes");
      }
      clazz.addSuperClass(parentClazz);
    }
        sc.jormclass = clazz;
      sc.jormclass.setAbstract(sc.isAbstract);
        if (projectName != null && mapperName != null) {
            ClassProject cp = clazz.getClassProject(projectName);
            if (cp == null) {
                cp = clazz.createClassProject(projectName);
            }
            Mapping mapping = cp.getMapping(mapperName);
            if (mapping != null) {
                //If the mapping is already defined then that means the jorm meta
                // information has been already defined.
                // => no meta object has been added.
                return;
            }
            mapping = cp.createMapping(mapperName);
            mb.createClassMapping(clazz, sc, mapping);
        }
    }

  private void createPrimitiveFields(SpeedoClass sc,
                                    String projectName,
                                    String mapperName,
                          JormMIMappingBuilder mb)
          throws SpeedoException, PException {
    Class clazz = sc.jormclass;
    ClassMapping cm = clazz.getClassProject(projectName)
        .getMapping(mapperName).getClassMapping();
        logger.log(BasicLevel.DEBUG, "Generate the Jorm MI for the class "
                + clazz.getFQName());
        for (Iterator fieldsIt = sc.fields.values().iterator();fieldsIt.hasNext();) {
            SpeedoField sp = (SpeedoField) fieldsIt.next();
            createPrimitiveField(sc, clazz, sp, cm, mb);
        }
    }
    private void createPrimitiveField(SpeedoClass sc,
            Class clazz,
            SpeedoField sp,
            ClassMapping cm,
            JormMIMappingBuilder mb)throws SpeedoException, PException {
        SpeedoExtension se = sp.getExtensionByKey(SpeedoProperties.FIELD_CONVERTER);
        PType ptype = null;
        String className = null;
        if (se != null) {
            try {
                UserFieldMapping ufm = (UserFieldMapping)
                        java.lang.Class.forName(se.value).newInstance();
                ptype = getPrimitivePType(ufm.getStorageType().getName());
                if (ptype == null) {
                    className = ufm.getStorageType().getName();
                }
            } catch (Exception e) {
                throw new SpeedoException(
                        "Impossible to instanciate the UserFieldMapping class '"
                        + se.value + "' for the field '" + sp.name
                        + "' of the class '" + sc.getFQName() + "':", e);
            }
        } else {
            Type type = Type.getType(sp.type);
            ptype = getPrimitivePType(type);
            if (ptype == null) {
                className = type.getClassName();
            }
        }
        if (ptype == null) {
            if (isPersistentClass(className, sc.moPackage.name, manager)) {
                //JM of a reference field will be defined later.
                return;
            } else {
                logger.log(BasicLevel.INFO, "The field '" + sc.getFQName()
                    + "." + sp.name + " is managed as a Serialized field.");
                ptype = PTypeSpace.SERIALIZED;
            }
        }
        logger.log(BasicLevel.DEBUG, "primitive field: " + sp.name + " / javatype: " + ptype.getJavaName());
        se = sp.getExtensionByKey(SpeedoProperties.SIZE);
        int size = PType.NOSIZE;
        if (se != null) {
            try {
                size = Integer.parseInt(se.value);
            } catch (NumberFormatException e) {
                logger.log(BasicLevel.ERROR, "The specified size for the field '"
                    + sp.name + "' of the class '" + sc.getFQName()
                    + "' cannot be parsed: " + se.value, e);
            }
        }
        int scale = PType.NOSIZE;
        se = sp.getExtensionByKey(SpeedoProperties.SCALE);
        if (se != null) {
            try {
                scale = Integer.parseInt(se.value);
            } catch (NumberFormatException e) {
                logger.log(BasicLevel.ERROR, "The specified scale for the field '"
                    + sp.name + "' of the class '" + sc.getFQName()
                    + "' cannot be parsed: " + se.value, e);
            }
        }
        PrimitiveElement pe = clazz.createPrimitiveElement(sp.name, ptype, size, scale);
        if (cm != null && mb != null) {
            mb.createFieldMapping(pe, sp, cm);
        }
    }

  /**
   * Creates the identifier name and its mapping for a persistent class.
   * @param sc is the SpeedoClass meta object describing the persistent which
   * the identifier has to be defined.
   * @param projectName is the jorm project name
   * @param mapperName is the mapper name
   * @param mb is the builder of the Jorm Mapping meta info
   * @param createdMOs is the list of created meta object (Class or
   * CompositeName).
   * @return a boolean value indicating if the identifier has been created. In
   * the inheritance case the identifier is inherited from the parent. If the
   * parent identifier is not defined, it is not possible to create the
   * identifier of the specified persistent class.
   */
  private boolean createIdentifierNameDef(SpeedoClass sc,
                                    String projectName,
                                    String mapperName,
                          JormMIMappingBuilder mb,
                          Collection createdMOs)
          throws SpeedoException, PException {
    ClassMapping cm = sc.jormclass.getClassProject(projectName)
        .getMapping(mapperName).getClassMapping();
    NameDef classNd = null;
    IdentifierMapping im = cm.getIdentifierMapping();
    if (im != null) {
      classNd = (NameDef) im.getLinkedMO();
      if (classNd != null) {
        return true;
      }
    }
    if (sc.getSuperClassName() == null) {
      classNd = sc.jormclass.createNameDef();
          nmf.getNamingManager(sc).defineClassIdentifierNameDef(
                  classNd, sc.jormclass, sc, cm, this, mb, createdMOs);
      if (cm != null) {
        cm.createIdentifierMapping(classNd);
      }
    } else {
      SpeedoClass parent = sc.getSpeedoClassFromContext(sc.getSuperClassName());
      im = parent.jormclass
          .getClassProject(projectName).getMapping(mapperName)
          .getClassMapping().getIdentifierMapping();
      if (im != null) {
        classNd = (NameDef) im.getLinkedMO();
        if (classNd != null) {
          cm.createIdentifierMapping(classNd);
        }
      }
    }
    if (debug) {
      logger.log(BasicLevel.DEBUG, "Create the identifier of the class '"
        + sc.getFQName() + "'"
        + (sc.getSuperClassName() == null ? ""
        : "(parent class name='" + sc.getSuperClassName() + "')")
        + ", namedef=" + classNd + ".");
    }
    return classNd != null;
  }

    /**
     * Builds the jorm meta objects representing the references owns by a persitent
     * class. It is supposed that if the reference targets a persistent class,
     * then the Class meta object and its NameDef are already defined.
     * @param sc is the Speedo meta object describing the class which the jorm
     * meta information must be built.
     * @param projectName is the project name for which the mapping must
     * be defined
     * @param mapperName is the mapper name for which the mapping must
     * be defined
     * @param mb is the build of the mapping part of the meta information
     * @param createdMOs is a result paramter. This collection must be fill with
     * the created Jorm Meta objects representing  a class or a composite name.
     * Here only the new used composite name will be added.
     */
    private void createReferences(SpeedoClass sc,
                                 String projectName,
                                 String mapperName,
                                 JormMIMappingBuilder mb,
                                 Collection createdMOs)
            throws SpeedoException, PException {
        Class clazz = manager.getClass(sc.getFQName());
        logger.log(BasicLevel.DEBUG, "Generate the Jorm MI for the references of class "
                + clazz.getFQName());
        Mapping mapping = null;
        ClassMapping cm = null;
        if (projectName != null && mapperName != null) {
            mapping = clazz.getClassProject(projectName)
                .getMapping(mapperName);
            cm = mapping.getClassMapping();
        }
        Iterator fieldsIt = sc.fields.values().iterator();
        //System.out.println("Manage reference of the class " + sc.getFQName());
        while (fieldsIt.hasNext()) {
            SpeedoField sp = (SpeedoField) fieldsIt.next();
          if (clazz.getTypedElement(sp.name) != null) {
                //the primitive element is already managed before(createJormClass)
                continue;
            }
          Type t = Type.getType(sp.type);
            String javatype = t.getClassName();
            if (!isGenClassRef(javatype)) {
                //                     reference to a class                   //
                //============================================================//
              if (debug) {
                    logger.log(BasicLevel.DEBUG, "Class reference field: "
                        + sp.name + " / javatype: " + javatype);
              }
                // reference to a class
                SpeedoClass tsc = sc.moPackage.xmlDescriptor
                        .getSpeedoClass(javatype, true);
                if (tsc == null) {
                    throw new SpeedoException("No persistent class '"
                            + javatype + "' found in the file: "
                            + sc.moPackage.xmlDescriptor.xmlFile);
                }
                Class tclass = manager.getClass(tsc.getFQName());
                if (tclass == null) {
                    manager.createClass(tsc.getFQName());
                }
                ClassRef cr = clazz.createClassRef(sp.name, tclass);
                NameDef refNd = cr.createRefNameDef();
                nmf.getNamingManager(tsc)
                  .defineClassReferenceNameDef(refNd, cr, sp, sc, cm, this, mb);
                if ( cm != null) {
                    cm.createReferenceMapping(sp.name, refNd);
                    cm.addDependency(tsc.getFQName());
                }

            } else {
                //                reference to a generic class                //
                //============================================================//
                String innerType = getInnerType(sp);
                if (innerType == null) {
                    throw new SpeedoException("The inner element type is " +
                            "required for the multivalued field '" + sp.name
                            + "' of the class '" + sc.getFQName()
                            + "' in the .jdo file '"
                            + sc.moPackage.xmlDescriptor.xmlFile + "'");
                }
                PType type = getPrimitivePType(innerType);
              if (type == null && !isPersistentClass(innerType, sc.moPackage.name, manager)) {
                logger.log(BasicLevel.INFO, "The field '" + sc.getFQName()
                        + "." + sp.name + " is managed as a Serialized field.");
                type = PTypeSpace.SERIALIZED;
              }
              if (debug) {
          logger.log(BasicLevel.DEBUG, "GenClass reference field: "
              + sp.name + " / javatype: " + javatype
              + " / innerType: " + innerType
            + " / ptype=" + (type == null ? null : type.getJavaName()));
              }
                GenClassRef gcr = clazz.createGenClassRef(sp.name, javatype);
                GenClassMapping gcm = null;
                ClassRef cr = null;
                SpeedoClass tsc = null;

                //element of the gen class
                if (type != null) {
                    // gen class of primitive type
                    gcr.createPrimitiveElement(type, PType.NOSIZE, PType.NOSIZE);
                } else if (!isGenClassRef(innerType)) {
                    // gen class of classref
                    tsc = sc.moPackage.xmlDescriptor.smi
                            .getSpeedoClass(innerType, sc.moPackage);
                    if (tsc == null) {
                        throw new SpeedoException("The persistent class '"
                                + sc.getFQName()
                                + "' tries to reference (througth the field '"
                                + sp.name
                                + "') the class '" + innerType
                                + "' not defined in the .jdo file '"
                                + sc.moPackage.xmlDescriptor.xmlFile + "'");
                    }
                    Class tclass = manager.getClass(tsc.getFQName());
                    if (tclass == null) {
                        throw new SpeedoException("The inner element class '"
                            + tsc.getFQName() + "' of the multivalued field '"
                            + sp.name + "' of the class '" + sc.getFQName()
                            + "' in the .jdo file '"
                            + sc.moPackage.xmlDescriptor.xmlFile
                                + "' has not been found among the persitent classes : "
                            + manager.getClasses());
                    }
                    cr = gcr.createClassRef(tclass);
                } else {
                    throw new SpeedoException(
                            "unmanaged the inner-element of the field '"
                            + sp.name + "' of the class '" + sc.getFQName()
                            + "' : " + innerType);
                }
                //Map the element of the generic class
                if (mapping != null) {
                    gcm = mb.createGenClassMapping(gcr, sp, mapping);
                    if (gcr.isPrimitive()) {
                        mb.createGenClassElementMapping(gcr.getPrimitiveElement(), sp, gcm);
                    } else {
                        NameDef elemNd = cr.createRefNameDef();
                        nmf.getNamingManager(tsc).defineClassReferenceNameDef(elemNd, cr, sp, sc, gcm, this, mb);
                        //fillNameDef(elemNd, tsc, sc, gcr, gcr, gcm, mb, false, true, true, createdMOs);
                        gcm.createReferenceMapping(sp.name, elemNd);
                        cm.addDependency(tsc.getFQName());
                    }
                }

                // reference to a generic class from the class
                NameDef refNd = gcr.createRefNameDef();
                nmf.getNamingManager(sc).defineGenClassReferenceNameDef(refNd, gcr, sp, sc, cm, this, mb);
                //fillNameDef(refNd, sc, sc, clazz, gcr, cm, mb, false, false, false, createdMOs);
                if (cm != null) {
                    cm.createReferenceMapping(sp.name, refNd);
                }

                //identifier of the gen class
                NameDef gcidNd = gcr.createIdNameDef();
                nmf.getNamingManager(sc).defineGenClassIdentifierNameDef(
                        gcidNd, gcr, sp, sc, gcm, this, mb);
                //fillNameDef(gcidNd, sc, sc, gcr, gcr, gcm, mb, true, true, true, createdMOs);
                if (gcm != null) {
                    gcm.createIdentifierMapping(gcidNd);
                }

                //index of the gen class
                java.lang.Class gcClass;
                try {
                    gcClass = java.lang.Class.forName(javatype);
                } catch (ClassNotFoundException e) {
                    throw new SpeedoException(
                            "The multivalued field '" + sp.name
                            + "' of the class '" + sc.getFQName()
                            + "' is not a well known class " + javatype, e);
                }
                if (isSubType(gcClass, java.util.List.class)) {
                    PrimitiveElement pe = gcr.createHiddenField(
                            LIST_INDEX, PTypeSpace.INT, PType.NOSIZE, PType.NOSIZE);
                    if (gcm != null) {
                        mb.createGenClassIndexMapping(pe, sp, gcm);
                    }
                    gcr.addIndexField(LIST_INDEX);
                } else if (isSubType(gcClass, java.util.Map.class)) {
          String keyfield = sp.getExtensionValueByKey(SpeedoProperties.KEY_FIELD);
          if (keyfield == null) {
            keyfield = MAP_INDEX;
          }
                    PrimitiveElement pe = gcr.createHiddenField(
                            keyfield, getMapKeyPType(sp), PType.NOSIZE, PType.NOSIZE);
                    if (gcm != null) {
                        mb.createGenClassIndexMapping(pe, sp, gcm);
                    }
                    gcr.addIndexField(pe.getName());
                }
            }
        }

    }

    private static final String HIDDEN_FIELD_CLASS_NAME = "speedo_class_name";
   
  private void mapInheritance(SpeedoClass sc,
                                 String projectName,
                                 String mapperName,
                                 JormMIMappingBuilder mb)
      throws SpeedoException, PException {
    ClassMapping cm = sc.jormclass.getClassProject(projectName)
        .getMapping(mapperName).getClassMapping();
    NameDef nd = (NameDef) cm.getIdentifierMapping().getLinkedMO();

    if (sc.inheritance != null && sc.inheritance.discriminator != null) {
        SpeedoDiscriminator sd = sc.inheritance.discriminator;
        String filter = null;
        if (sd.expression != null) {
        filter = sd.expression;
        } else if (sd.elements.size() == 1) {
                SpeedoElement se = (SpeedoElement) sd.elements.get(0);
                if (se instanceof SpeedoField) {
                    filter = ((SpeedoField) se).name;
                } else if (se instanceof SpeedoNoFieldColumn) {
                    filter = HIDDEN_FIELD_CLASS_NAME;
                } else {
                    throw new SpeedoException("Unmanaged filter element: " + se);
                }
        } else {
            throw new SpeedoException(
                    "Composite inheritance discriminator not yet supported in Speedo");
        }
        if (filter != null) {
            sc.jormclass.setInheritanceFilter(nd, filter);
            logger.log(BasicLevel.DEBUG, "Assign filter: " + filter);
        }
            if (sc.inheritance.discriminator.elements != null
                    && sc.inheritance.discriminator.elements.size() == 1) {
                SpeedoElement se = (SpeedoElement) sc.inheritance.discriminator.elements.get(0);
                if (se instanceof SpeedoNoFieldColumn) {
                    if (sc.getSuper() == null) {
                        // The discriminator is a column not mapped to a
                        // persistent field. then we have to create a constant
                        // hidden field.
                        PrimitiveElement pe = sc.jormclass.createHiddenField(
                            HIDDEN_FIELD_CLASS_NAME, PTypeSpace.STRING, PType.NOSIZE, PType.NOSIZE);
                        pe.setStatus(PrimitiveElement.CONSTANT_PERSISTENT);
                        mb.createFieldMapping(pe, (SpeedoNoFieldColumn) se, cm);
                    }
                    if (sc.inheritance.discriminator.strategy ==
                                SpeedoDiscriminator.STRATEGY_CLASS_NAME
                                && sc.inheritance.discriminatorValues != null) {
                        // declare the constant value of the field
                        sc.jormclass.setConstantValue(HIDDEN_FIELD_CLASS_NAME,
                                (String) sc.inheritance.discriminatorValues.get(se));
                    }
                }
            }
    }
    if (sc.inheritance != null && sc.inheritance.discriminatorValues != null) {
        Object key = sc.inheritance.discriminatorValues.values().iterator().next();
          logger.log(BasicLevel.DEBUG, "Assign key: " + key);
      sc.jormclass.setInheritanceNamingKey(nd, key);
    }

    if (sc.getSuperClassName() == null) {
      return;
    }
    SpeedoClass parent = sc.getSpeedoClassFromContext(sc.getSuperClassName());
    String im = sc.getExtensionValueByKey(SpeedoProperties.INHERITANCE_MAPPING);

    // Map the inherited field if required
    if (sc.inheritance.isHorizontalMapping()) {
        for (Iterator it = sc.inheritance.remappedInheritedFields.values().iterator(); it.hasNext();) {
                SpeedoInheritedField sif = (SpeedoInheritedField) it.next();
        if (debug) {
          logger.log(BasicLevel.DEBUG, "Map the inherited field '"
            + sif.name + "'.");
        }
                TypedElement te = sif.inheritedField.moClass.jormclass.getTypedElement(sif.inheritedField.name);
                if (te == null) {
                    throw new SpeedoException("No inherited field '"
                            + sif.name + "' found from "
                            + sc.getSourceDesc());
                } else if (te instanceof PrimitiveElement) {
          mb.createFieldMapping((PrimitiveElement) te, sif, cm);
                } else if (te instanceof ClassRef) {
                    ClassRef cr = (ClassRef) te;
                    //Keep the same namedef than in the parent
                    //but map the field(s) used in name def on column defined
                    // in SpeedoInheritedField meta object.
                    NameDef refNd = (NameDef) cr.getRefNameDef().iterator().next();
                    cm.createReferenceMapping(sif.inheritedField.name, refNd);
                    //create PEM for each field used in the NameDef
                  mb.createClassRefNameDefMapping(cm, refNd, sif);
                }
            }
    } else if (sc.inheritance.isVerticalMapping()) {
        //TODO
    }
  }

    private boolean isSubType(java.lang.Class c1, java.lang.Class c2) {
        if (c1 == null) {
            return false;
        }
        if (c1 == c2) {
            return true;
        }
        if (c2.isInterface()) {
            java.lang.Class[] cs = c1.getInterfaces();
            for(int i = 0; i<cs.length; i++) {
                if (isSubType(cs[i], c2)) {
                    return true;
                }
            }
        }
        return isSubType(c1.getSuperclass(), c2);
    }

    private PType getMapKeyPType(SpeedoField sf) throws SpeedoException {
        SpeedoMap sm = (SpeedoMap) sf.jdoTuple;
        if (sm.keyType == null) {
            throw new SpeedoException(
                "It is required to define a key-type for the Map field'"
                + sf.name + "' of the class '" + sf.moClass.getFQName() +"' ");
        }
        PType res = getPrimitivePType((String) sm.keyType);
      boolean isPersistClass = isPersistentClass(
          (String) sm.keyType, sf.moClass.moPackage.name, manager);
      if (res == null && !isPersistClass) {
        logger.log(BasicLevel.INFO, "The field '" + sf.moClass.getFQName()
                + "." + sf.name + " is managed as a Serialized field.");
        res = PTypeSpace.SERIALIZED;
      }
        if (res == null) {
            throw new SpeedoException("The key-type '" + sm.keyType
                    + "' of the Map field'" + sf.name + "' of the class '"
                    + sf.moClass.getFQName() +"' is not supported");
        }
        return res;
    }

    /**
     * Fill the name def of an identifier or a reference
     * @param nd is the name def to fill
     * @param isIdentifier indicates if the name represents an identifier (true)
     * or a reference (false).
     * @param isInGenClass indicates if the name is defined in a generic class
     * (true) of in a class (false).
     * @param ref meta object which the name def must be
     * defined. This value is used only in the case of isIdentifier == false and
     * isInGenClass == false.
     * @param tsc is the speedo meta object representing the referenced class.
     * This value is used only in the case of isIdentifier == false.
     * @param mo is the jorm meta object hosting the name def and on which the
     * eventual hidden field will be created.
     * @param hcm if the mapping structure hosting the mapping of the reference.
     * This value must be ClassMapping or GenClassMapping instance.
     * @param mb is the mapping builder permitting the creation of the mapping
     * part.
     * @param createdMOs is a result paramter. This collection must be fill with
     * the created Jorm Meta objects representing  a class or a composite name.
     * Here only the new used composite name will be added.
     * @throws SpeedoException if the speedo meta information is not completly
     * defined.
    private void _fillNameDef(NameDef nd,
                             SpeedoClass tsc,
                             SpeedoClass ssc,
                             MetaObject mo,
                             Reference ref,
                             CommonClassMapping hcm,
                             JormMIMappingBuilder mb,
                             boolean isIdentifier,
                             boolean isInGenClass,
                             boolean createField,
                             Collection createdMOs)
            throws SpeedoException, PException {
        nmf.getNamingManager(tsc)
                .fillNameDef(this,manager, nd, tsc, ssc, mo, ref, hcm,
                        mb, isIdentifier, isInGenClass, createField, createdMOs);
    }
     */

    /**
     * Calculates the prefix of a field use in a name def.
     * @param ref is the meta object of the reference if the namedef is
     * used for  a reference.
     * @param isIdentifier indicates if the namedef is used for an identifier
     * (true) or if the namedef is used for a reference (false).
     * @param isInGenClass indicates if the namedef is used in a Generic class
     * (true) or if the namedef is used in a class (false).
     * @return a string value (never null) representing the prefix of a name
     * def field.
     */
    public String getNameDefFieldPrefix(Reference ref,
                                         boolean isIdentifier,
                                         boolean isInGenClass,
                                         SpeedoField sf) throws SpeedoException {
        if (isIdentifier) {
            if (isInGenClass
                && sf.relationType == SpeedoField.ONE_MANY_BI_RELATION) {
                //In case of ONE-MANY relation ship with Inheritance in the
                // MANY side the hidden field name in the GenClass MUST have
                // the same name than the hidden field in the referenced class
                // Otherwise the alias names do not correspond in the SQL
                // request generated by JORM for in inheritance.
                return sf.getReverseField().name + '_';
            }
            return "";
        } else {
            if (isInGenClass) {
                if (sf.relationType == SpeedoField.ONE_MANY_BI_RELATION) {
                    //In case of ONE-MANY relation ship with Inheritance in the
                    // MANY side the hidden field name in the GenClass MUST have
                    // the same name than the hidden field in the referenced class
                    // Otherwise the alias names do not correspond in the SQL
                    // request generated by JORM for in inheritance.
                    return "";
                } else {
                    return GENCLASS_ELM_PREFIX;
                }
            } else {
                if (ref instanceof GenClassRef) {
                    //The reference of the GCR is mapped over the class identifer
                    // fields
                    return "";
                } else {
                    return ref.getName() + '_';
                }
            }
        }
    }

    /**
     * It creates a field of a name def. This field will be hidden
     * @param mo is the jorm meta object hosting the field to create
     * @param fn is the name of the field to create
     * @param type is the type of the field to create
     * @param size is the size of the field to create
     * @return the jorm meta object representing the namedef field
     */
    public ScalarField createNameDefField(MetaObject mo,
                                          String fn,
                                          PType type, int size, int scale)
            throws SpeedoException {
        ScalarField sf;
        if (mo instanceof Class) {
            sf = ((Class) mo).createHiddenField(fn, type, size, scale);
        } else if (mo instanceof GenClassRef) {
            sf = ((GenClassRef) mo).createHiddenField(fn, type, size, scale);
        } else {
            throw new SpeedoException(
                    "Impossible to create hidden field on this meta object: " + mo);
        }
        return sf;
    }

    /**
     * It creates a field of a name def. This field will be hidden
     * @param mo is the jorm meta object hosting the field to create
     * @param fn is the name of the field to create
     * @param type is the type of the field to create
     * @return the jorm meta object representing the namedef field
     */
    public ScalarField createNameDefField(MetaObject mo,
                                          String fn,
                                          PType type)
            throws SpeedoException {
        return createNameDefField(mo, fn, type, PType.NOSIZE, PType.NOSIZE);
    }

    /**
     * Retrieves the jorm type matching to primitive type. It converts a Type
     * defined in ASM into a PType defined in Jorm. If the type is not a jorm
     * primitive type then a null value is returned.
     */
    public PType getPrimitivePType(Type t) {
        switch (t.getSort()) {
        case Type.BOOLEAN:
            return PTypeSpace.BOOLEAN;
        case Type.CHAR:
            return PTypeSpace.CHAR;
        case Type.BYTE:
            return PTypeSpace.BYTE;
        case Type.SHORT:
            return PTypeSpace.SHORT;
        case Type.INT:
            return PTypeSpace.INT;
        case Type.FLOAT:
            return PTypeSpace.FLOAT;
        case Type.LONG:
            return PTypeSpace.LONG;
        case Type.DOUBLE:
            return PTypeSpace.DOUBLE;
        case Type.ARRAY:
        PType innerType = getPrimitivePType(t.getElementType());
        if (innerType !=null) {
          if (innerType == PTypeSpace.CHAR) {
            return PTypeSpace.CHARARRAY;
          } else if (innerType == PTypeSpace.BYTE) {
            return PTypeSpace.BYTEARRAY;
          } else {
            return PTypeSpace.SERIALIZED;
          }
        }
        return null;
        case Type.OBJECT:
      default:
            String cn = t.getClassName();
          PType res = getPrimitivePType(cn);
          if (res == null && !isPersistentClass(cn, null, manager)) {
                return PTypeSpace.SERIALIZED;
            } else {
              return res;
            }
      }
    }

    private PType getPrimitivePType(String cn) {
        for (int i = 0; i < PTypeSpace.PREDEFINEDPTYPES.length; i++) {
            if (PTypeSpace.PREDEFINEDPTYPES[i] != PTypeSpace.REFTOP
                && PTypeSpace.PREDEFINEDPTYPES[i].getJavaName().equals(cn)) {
                return PTypeSpace.PREDEFINEDPTYPES[i];
            }
        }
        if (java.sql.Date.class.getName().equals(cn)) {
            return PTypeSpace.DATE;
        } else if (java.sql.Time.class.getName().equals(cn)) {
            return PTypeSpace.DATE;
        } else if (java.sql.Timestamp.class.getName().equals(cn)) {
            return PTypeSpace.DATE;
        } else if (java.util.Locale.class.getName().equals(cn)) {
            return PTypeSpace.STRING;
        } else {
        return null;
        }
    }

  private boolean isPersistentClass(String cn, String currentPackage, Manager mgr) {
    if (isGenClassRef(cn)) {
      return true;
    }
    if (cn.indexOf('.') != -1 || currentPackage == null) {
      return mgr.getClass(cn) != null;
    } else {
      return mgr.getClass(currentPackage + '.' + cn) != null;
    }
  }

    /**
     * Indicates if the string representing a java type is a generic class (
     * java.util.Collection | java.util.Set | java.util.Map
     * @param javatype
     * @return
     */
    private boolean isGenClassRef(String javatype) {
        int i=0;
        while(i<AbstractSpeedoGenerator.GC_IMPL .length
                && !AbstractSpeedoGenerator.GC_IMPL[i][0].equals(javatype)) {
            i++;
        }
        return i<AbstractSpeedoGenerator.GC_IMPL .length;
    }

    /**
     * Retrieves the type of a generic class element.
     * @param sp is the field which represents the generic class
     * @return a String value representing the java type of the element, or null
     * if the Speedofield does not represents a generic class.
     */
    private String getInnerType(SpeedoField sp) {
        if (sp.jdoTuple instanceof SpeedoCollection) {
            return (String) ((SpeedoCollection) sp.jdoTuple).elementType;
        } else if (sp.jdoTuple instanceof SpeedoMap) {
            return (String) ((SpeedoMap) sp.jdoTuple).valueType;
        }
        return null;
    }


    /**
     * retrieves the start of a pretty error message.
     */
    public String getErrorMessage(SpeedoClass sc, MetaObject mo, Reference ref) {
        String fqcn;
        if (mo == null) {
            fqcn = "null";
        } else if (mo instanceof Class) {
            fqcn = ((Class) mo).getFQName();
        } else if (mo instanceof GenClassRef) {
            fqcn = ((GenClassRef) mo).getGenClassId();
        } else {
            fqcn = mo.toString();
        }
        String res = "Impossible to define an user identifier for the ";
        if (ref == null) {
            res += "identifier of the class '" + fqcn;
        } else {
            res += "reference '" + ref.getName()
                    + "' from the class '" + fqcn
                    + "' to the class '" + sc.getFQName();
        }
        return res  + "': ";
    }

    public PrimitiveElement getPrimitiveField(MetaObject mo, String name) {
        if (mo instanceof Class) {
            return (PrimitiveElement) ((Class) mo).getTypedElement(name);
        } else if (mo instanceof GenClassRef) {
            return ((GenClassRef) mo).getHiddenField(name);
        } else {
            return null;
        }
    }
   
    public Manager getManager(MetaObject mo) {
        MetaObject current = mo;
        while(!(current instanceof Manager)) {
            current = current.getParent();
        }
        return (Manager) current;
    }
}
TOP

Related Classes of org.objectweb.speedo.generation.jorm.JormMIBuilder

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.