Package railo.runtime.orm.hibernate

Source Code of railo.runtime.orm.hibernate.HBMCreator

package railo.runtime.orm.hibernate;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import railo.loader.util.Util;
import railo.runtime.Component;
import railo.runtime.PageContext;
import railo.runtime.component.Property;
import railo.runtime.db.DatasourceConnection;
import railo.runtime.exp.PageException;
import railo.runtime.orm.ORMUtil;
import railo.runtime.type.Collection;
import railo.runtime.type.Collection.Key;
import railo.runtime.type.Struct;

public class HBMCreator {
 
 
  private static final Collection.Key PROPERTY = CommonUtil.createKey("property");
  private static final Collection.Key LINK_TABLE = CommonUtil.createKey("linktable");
  private static final Collection.Key CFC = CommonUtil.createKey("cfc");
  private static final Collection.Key GENERATOR = CommonUtil.createKey("generator");
  private static final Collection.Key PARAMS = CommonUtil.createKey("params");
  private static final Collection.Key SEQUENCE = CommonUtil.createKey("sequence");
  private static final Collection.Key UNIQUE_KEY_NAME = CommonUtil.createKey("uniqueKeyName");
  private static final Collection.Key GENERATED = CommonUtil.createKey("generated");
  private static final Collection.Key FIELDTYPE = CommonUtil.createKey("fieldtype");
  private static final Collection.Key KEY = CommonUtil.createKey("key");
  private static final Collection.Key TYPE = CommonUtil.createKey("type");
  
  public static void createXMLMapping(PageContext pc,DatasourceConnection dc, Component cfc,Element hibernateMapping,SessionFactoryData data) throws PageException {
   
    // MUST Support for embeded objects
    Struct meta = cfc.getMetaData(pc);
   
    String extend = cfc.getExtends();
    boolean isClass=Util.isEmpty(extend);

    // MZ: Fetches all inherited persistent properties
    //Property[] _props=getAllPersistentProperties(pc,cfc,dc,meta,isClass);

    Property[] _props=getProperties(pc,cfc,dc,meta,isClass, true,data);

   

    Map<String, PropertyCollection> joins=new HashMap<String, PropertyCollection>();
    PropertyCollection propColl = splitJoins(cfc,joins, _props,data);
   
   
   
    // create class element and attach
    Document doc = CommonUtil.getDocument(hibernateMapping);
   
    StringBuilder comment=new StringBuilder();
    comment.append("\nsource:").append(cfc.getPageSource().getDisplayPath());
    comment.append("\ncompilation-time:").append(CommonUtil.createDateTime(HibernateUtil.getCompileTime(pc,cfc.getPageSource()))).append("\n");
   
    hibernateMapping.appendChild(doc.createComment(comment.toString()));
   
    //print.e(cfc.getAbsName()+";"+isClass+" -> "+cfci.getBaseAbsName()+":"+cfci.isBasePeristent());
    if(!isClass && !cfc.isBasePeristent()) {
      isClass=true;
    }
   
   
    Element join=null;
    boolean doTable=true;
   
    Element clazz;
    if(isClass)  {
      clazz = doc.createElement("class");
      hibernateMapping.appendChild(clazz);
    }
    // extended CFC
    else{
      // MZ: Fetches one level deep
      _props=getProperties(pc,cfc,dc,meta,isClass, false,data);
      // MZ: Reinitiate the property collection
      propColl = splitJoins(cfc,joins, _props,data);

      String ext = CommonUtil.last(extend,'.').trim();
      try {
        Component base = data.getEntityByCFCName(ext, false);
        ext = HibernateCaster.getEntityName(base);
      }
      catch(Throwable t){}
     
     
      String discriminatorValue = toString(cfc,null,meta,"discriminatorValue",data);
      if(!Util.isEmpty(discriminatorValue,true)) {
        doTable=false;
        clazz = doc.createElement("subclass");
        hibernateMapping.appendChild(clazz);
            //addClassAttributes(classNode);
            clazz.setAttribute("extends", ext);
            clazz.setAttribute("discriminator-value", discriminatorValue);
           
            String joincolumn = toString(cfc,null,meta,"joincolumn",false,data);
            if(!Util.isEmpty(joincolumn)){
              join = doc.createElement("join");
              clazz.appendChild(join);
              doTable=true;
              Element key = doc.createElement("key");
              join.appendChild(key);
              key.setAttribute("column", formatColumn(joincolumn,data));
            }
           
      }
      else {
        // MZ: Match on joinColumn for a joined subclass, otherwise use a union subclass
        String joinColumn = toString(cfc,null,meta,"joincolumn",false,data);
        if (!Util.isEmpty(joinColumn,true)) {
          clazz = doc.createElement("joined-subclass");
          hibernateMapping.appendChildclazz);
          clazz.setAttribute("extends",ext);
          Element key = doc.createElement("key");
          clazz.appendChild(key);
          key.setAttribute("column", formatColumn(joinColumn,data));
        }
        else {
          // MZ: When no joinColumn exists, default to an explicit table per class
          clazz = doc.createElement("union-subclass");
          clazz.setAttribute("extends",ext);
          doTable = true;
          hibernateMapping.appendChildclazz);
        }

      }
    }

    //createXMLMappingTuplizer(clazz,pc);

    addGeneralClassAttributes(pc,cfc,meta,clazz,data);
    String tableName=getTableName(pc,meta,cfc,data);
   
    if(join!=null) clazz=join;
    if(doTable)addGeneralTableAttributes(pc,cfc,meta,clazz,data);
   
   
       
       
        Struct columnsInfo=null;
        if(data.getORMConfiguration().useDBForMapping()){
          columnsInfo = data.getTableInfo(dc,getTableName(pc, meta, cfc,data));
        }

        if(isClass)setCacheStrategy(cfc,null,doc, meta, clazz,data);
       
    // id
        if(isClass) addId(cfc,doc,clazz,meta,propColl,columnsInfo,tableName,data);
       
        // discriminator
        if(isClass) addDiscriminator(cfc,doc,clazz,pc,meta,data);
       
    // version
        if(isClass)addVersion(cfc,clazz,pc, propColl,columnsInfo,tableName,data);
   
    // property
    addProperty(cfc,clazz,pc, propColl,columnsInfo,tableName,data);
   
    // relations
    addRelation(cfc,clazz,pc, propColl,columnsInfo,tableName,dc,data);

    // collection
    addCollection(cfc,clazz,pc, propColl,columnsInfo,tableName,data);
   
    // join
    addJoin(cfc,clazz,pc, joins,columnsInfo,tableName,dc,data);

   
  }
 
  private static Property[] getProperties(PageContext pc, Component cfc, DatasourceConnection dc, Struct meta, boolean isClass, boolean recursivePersistentMappedSuperclass,SessionFactoryData data) throws PageException, PageException {
    Property[] _props;
    if (recursivePersistentMappedSuperclass) {
      _props = CommonUtil.getProperties(cfc,true, true, true, true);
    }
    else {
      _props = cfc.getProperties(true);
    }

    if(isClass && _props.length==0 && data.getORMConfiguration().useDBForMapping()){
      if(meta==null)meta = cfc.getMetaData(pc);
          _props=HibernateUtil.createPropertiesFromTable(dc,getTableName(pc, meta, cfc, data));
        }
    return _props;
  }

  private static void addId(Component cfc,Document doc, Element clazz, Struct meta, PropertyCollection propColl, Struct columnsInfo, String tableName, SessionFactoryData data) throws PageException {
    Property[] _ids = getIds(cfc,propColl,data);
   
        //Property[] _ids = ids.toArray(new Property[ids.size()]);
       
        if(_ids.length==1)
          createXMLMappingId(cfc,clazz, _ids[0],columnsInfo,tableName,data);
        else if(_ids.length>1)
          createXMLMappingCompositeId(cfc,clazz, _ids,columnsInfo,tableName,data);
        else
          throw ExceptionUtil.createException(data,cfc,"missing id property for entity ["+HibernateCaster.getEntityName(cfc)+"]",null);
  }
 

  private static PropertyCollection splitJoins(Component cfc,Map<String, PropertyCollection> joins,Property[] props,SessionFactoryData data) {
    Struct sct=CommonUtil.createStruct();
    ArrayList<Property> others = new ArrayList<Property>();
    java.util.List<Property> list;
    String table;
    Property prop;
    String fieldType;
    boolean isJoin;
    for(int i=0;i<props.length;i++){
      prop=props[i];
      table=getTable(cfc,prop,data);
      // joins
      if(!Util.isEmpty(table,true)){
        isJoin=true;
        // wrong field type
        try {
          fieldType = toString(cfc, prop, sct, FIELDTYPE,false,data);
         
          if("collection".equalsIgnoreCase(fieldType)) isJoin=false;
          else if("primary".equals(fieldType)) isJoin=false;
          else if("version".equals(fieldType)) isJoin=false;
          else if("timestamp".equals(fieldType)) isJoin=false;
        }
        catch (PageException e) {}
       
        // missing column
        String columns=null;
        try {
          if(ORMUtil.isRelated(props[i])){
                columns=toString(cfc,props[i], prop.getDynamicAttributes(), "fkcolumn",data);
              }
              else {
                columns=toString(cfc,props[i], prop.getDynamicAttributes(), "joincolumn",data);
              }
        }
        catch(PageException e){}
        if(Util.isEmpty(columns)) isJoin=false;
       
        if(isJoin){
          table=table.trim();
          list = (java.util.List<Property>) sct.get(table,null);
          if(list==null){
            list=new ArrayList<Property>();
            sct.setEL(CommonUtil.createKey(table), list);
          }
          list.add(prop);
          continue;
        }
      }
      others.add(prop);
    }
   
    // fill to joins
    Iterator<Entry<Key, Object>> it = sct.entryIterator();
    Entry<Key, Object> e;
    while(it.hasNext()){
      e = it.next();
      list=(java.util.List<Property>) e.getValue();
      joins.put(e.getKey().getString(), new PropertyCollection(e.getKey().getString(),list));
    }
   
   
   
    return new PropertyCollection(null,others);
  }
 
 
 
 

  private static Property[] getIds(Component cfc,PropertyCollection pc,SessionFactoryData data) {
    return getIds(cfc,pc.getProperties(), pc.getTableName(),false,data);
  }
 
  private static Property[] getIds(Component cfc,Property[] props,String tableName, boolean ignoreTableName,SessionFactoryData data) {
    ArrayList<Property> ids=new ArrayList<Property>();
        for(int y=0;y<props.length;y++){
          if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue;
         
         
          String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null);
      if("id".equalsIgnoreCase(fieldType) || CommonUtil.listFindNoCaseIgnoreEmpty(fieldType,"id",',')!=-1)
        ids.add(props[y]);
    }
       
        // no id field defined
        if(ids.size()==0) {
          String fieldType;
          for(int y=0;y<props.length;y++){
            if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue;
              fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null);
          if(Util.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase("id")){
            ids.add(props[y]);
            props[y].getDynamicAttributes().setEL(FIELDTYPE, "id");
          }
        }
        }
       
        // still no id field defined
        if(ids.size()==0 && props.length>0) {
          String owner = props[0].getOwnerName();
      if(!Util.isEmpty(owner)) owner=CommonUtil.last(owner, '.').trim();
         
          String fieldType;
          if(!Util.isEmpty(owner)){
            String id=owner+"id";
            for(int y=0;y<props.length;y++){
              if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue;
                  fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null);
            if(Util.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase(id)){
              ids.add(props[y]);
              props[y].getDynamicAttributes().setEL(FIELDTYPE, "id");
            }
          }
          }
        }
        return ids.toArray(new Property[ids.size()]);
  }






  private static void addVersion(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,SessionFactoryData data) throws PageException {
      Property[] props = propColl.getProperties();
    for(int y=0;y<props.length;y++){
      String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null);
      if("version".equalsIgnoreCase(fieldType))
        createXMLMappingVersion(clazz,pc, cfc,props[y],data);
      else if("timestamp".equalsIgnoreCase(fieldType))
        createXMLMappingTimestamp(clazz,pc,cfc, props[y],data);
    }
  }



  private static void addCollection(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,SessionFactoryData data) throws PageException {
    Property[] props = propColl.getProperties();
    for(int y=0;y<props.length;y++){
      String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column");
      if("collection".equalsIgnoreCase(fieldType))
        createXMLMappingCollection(clazz,pc, cfc,props[y],data);
    }
  }
 
 
  private static void addJoin(Component cfc,Element clazz, PageContext pc,Map<String, PropertyCollection> joins, Struct columnsInfo, String tableName,DatasourceConnection dc, SessionFactoryData data) throws PageException {
       
    Iterator<Entry<String, PropertyCollection>> it = joins.entrySet().iterator();
    Entry<String, PropertyCollection> entry;
    while(it.hasNext()){
      entry = it.next();
      addJoin(cfc,pc,columnsInfo,clazz,entry.getValue(),dc,data);
    }
   
   
   
    }
 
  private static void addJoin(Component cfc,PageContext pc,Struct columnsInfo, Element clazz, PropertyCollection coll, DatasourceConnection dc, SessionFactoryData data) throws PageException {
    String table = coll.getTableName();
    Property[] properties = coll.getProperties();
    if(properties.length==0) return;
   
    Document doc = CommonUtil.getDocument(clazz);
   
    Element join = doc.createElement("join");
        clazz.appendChild(join);
   
        join.setAttribute("table", escape(HibernateUtil.convertTableName(data,coll.getTableName())));
        //addTableInfo(joinNode, table, schema, catalog);
       
        Property first = properties[0];
        String schema = null, catalog=null, mappedBy=null, columns=null;
        if(ORMUtil.isRelated(first)){
          catalog=toString(cfc,first, first.getDynamicAttributes(), "linkcatalog",data);
          schema=toString(cfc,first, first.getDynamicAttributes(), "linkschema",data);
          columns=toString(cfc,first, first.getDynamicAttributes(), "fkcolumn",data);
         
        }
        else {
          catalog=toString(cfc,first, first.getDynamicAttributes(), "catalog",data);
          schema=toString(cfc,first, first.getDynamicAttributes(), "schema",data);
          mappedBy=toString(cfc,first, first.getDynamicAttributes(), "mappedby",data);
          columns=toString(cfc,first, first.getDynamicAttributes(), "joincolumn",data);
        }

        if(!Util.isEmpty(catalog)) join.setAttribute("catalog", catalog);
        if(!Util.isEmpty(schema)) join.setAttribute("schema", schema);
       
        Element key = doc.createElement("key");
        join.appendChild(key);
        if(!Util.isEmpty(mappedBy)) key.setAttribute("property-ref", mappedBy);
        setColumn(doc, key, columns,data);
       
        addProperty(cfc,join,pc, coll,columnsInfo,table,data);
    int count=addRelation(cfc,join,pc, coll,columnsInfo,table,dc,data);
       
    if(count>0) join.setAttribute("inverse", "true");
     
   
  }







 



  private static int addRelation(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName, DatasourceConnection dc, SessionFactoryData data) throws PageException {
      Property[] props = propColl.getProperties();
    int count=0;
      for(int y=0;y<props.length;y++){
      String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column");
      if("one-to-one".equalsIgnoreCase(fieldType)){
        createXMLMappingOneToOne(clazz,pc, cfc,props[y],data);
        count++;
      }
      else if("many-to-one".equalsIgnoreCase(fieldType)){
        createXMLMappingManyToOne(clazz,pc, cfc,props[y],propColl,data);
        count++;
      }
      else if("one-to-many".equalsIgnoreCase(fieldType)){
        createXMLMappingOneToMany(cfc,propColl,clazz,pc, props[y],data);
        count++;
      }
      else if("many-to-many".equalsIgnoreCase(fieldType)){
        createXMLMappingManyToMany(cfc,propColl,clazz,pc, props[y],dc,data);
        count++;
      }
    }
      return count;
  }



  private static void addProperty(Component cfc,Element clazz, PageContext pc, PropertyCollection propColl, Struct columnsInfo, String tableName, SessionFactoryData data) throws PageException {
    Property[] props = propColl.getProperties();
    for(int y=0;y<props.length;y++){
      String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column");
      if("column".equalsIgnoreCase(fieldType))
        createXMLMappingProperty(clazz,pc,cfc, props[y],columnsInfo,tableName,data);
    }
  }



  private static void addDiscriminator(Component cfc,Document doc,Element clazz, PageContext pc,Struct meta,SessionFactoryData data) throws DOMException, PageException {
   
       String str = toString(cfc,null,meta,"discriminatorColumn",data);
       if(!Util.isEmpty(str,true)){
         Element disc = doc.createElement("discriminator");
         clazz.appendChild(disc);
         disc.setAttribute("column",formatColumn(str,data));
       }
      

     
     
  }



  private static void addGeneralClassAttributes(PageContext pc, Component cfc, Struct meta, Element clazz, SessionFactoryData data) throws PageException {
     
      // name
    clazz.setAttribute("node", HibernateCaster.toComponentName(cfc));
   
      // entity-name
      String str=toString(cfc,null,meta,"entityname",data);
    if(Util.isEmpty(str,true)) str=HibernateCaster.getEntityName(cfc);
    clazz.setAttribute("entity-name",str);
   

        // batch-size
        Integer i = toInteger(cfc,meta,"batchsize",data);
        if(i!=null && i.intValue()>0)clazz.setAttribute("batch-size",CommonUtil.toString(i));
   
    // dynamic-insert
        Boolean b = toBoolean(cfc,meta,"dynamicinsert",data);
        if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-insert","true");
       
        // dynamic-update
        b=toBoolean(cfc,meta,"dynamicupdate",data);
        if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-update","true");
       
    // lazy (dtd defintion:<!ATTLIST class lazy (true|false) #IMPLIED>)
        b=toBoolean(cfc,meta,"lazy",data);
        if(b==null) b=Boolean.TRUE;
        clazz.setAttribute("lazy",CommonUtil.toString(b.booleanValue()));
   
        // select-before-update
        b=toBoolean(cfc,meta,"selectbeforeupdate",data);
        if(b!=null && b.booleanValue())clazz.setAttribute("select-before-update","true");

        // optimistic-lock
        str=toString(cfc,null,meta,"optimisticLock",data);
        if(!Util.isEmpty(str,true)) {
          str=str.trim().toLowerCase();
          if("all".equals(str) || "dirty".equals(str) || "none".equals(str) || "version".equals(str))
            clazz.setAttribute("optimistic-lock",str);
          else
            throw ExceptionUtil.createException(data,cfc,"invalid value ["+str+"] for attribute [optimisticlock] of tag [component], valid values are [all,dirty,none,version]",null);
        }
       
        // read-only
        b=toBoolean(cfc,meta,"readOnly",data);
        if(b!=null && b.booleanValue()) clazz.setAttribute("mutable", "false");
       
        // rowid
        str=toString(cfc,null,meta,"rowid",data);
        if(!Util.isEmpty(str,true)) clazz.setAttribute("rowid",str);
       
        // where
        str=toString(cfc,null,meta,"where",data);
        if(!Util.isEmpty(str,true)) clazz.setAttribute("where", str);

      
  }
  private static void addGeneralTableAttributes(PageContext pc, Component cfc, Struct meta, Element clazz,SessionFactoryData data) throws PageException {
     // table
        clazz.setAttribute("table",escape(getTableName(pc,meta,cfc,data)));
       
        // catalog
        String str = toString(cfc,null,meta,"catalog",data);
        if(str==null)// empty string is allowed as input
          str=data.getORMConfiguration().getCatalog();
        if(!Util.isEmpty(str,true)) clazz.setAttribute("catalog", str);
       
        // schema
        str=toString(cfc,null,meta,"schema",data);
        if(str==null)// empty string is allowed as input
          str=data.getORMConfiguration().getSchema();
        if(!Util.isEmpty(str,true)) clazz.setAttribute( "schema", str);
       
  }
  private static String escape(String str) {
    if(HibernateUtil.isKeyword(str)) return "`"+str+"`";
    return str;
  }






  private static String getTableName(PageContext pc, Struct meta, Component cfc,SessionFactoryData data) throws PageException {
    String tableName=toString(cfc,null,meta,"table",data);
    if(Util.isEmpty(tableName,true))
      tableName=HibernateCaster.getEntityName(cfc);
    return HibernateUtil.convertTableName(data,tableName);
  }
 
  private static String getTable(Component cfc,Property prop,SessionFactoryData data) {
    try {
      return HibernateUtil.convertTableName(data,toString(cfc,prop, prop.getDynamicAttributes(), "table",data));
    } catch (PageException e) {
      return null;
    }
  }
 
  private static boolean hasTable(Component cfc,Property prop,String tableName,SessionFactoryData data) {
    String t = getTable(cfc,prop,data);
    boolean left=Util.isEmpty(t,true);
    boolean right=Util.isEmpty(tableName,true);
    if(left && right) return true;
    if(left || right) return false;
    return tableName.trim().equalsIgnoreCase(t.trim());
  }






  private static void createXMLMappingCompositeId(Component cfc,Element clazz, Property[] props,Struct columnsInfo,String tableName, SessionFactoryData data) throws PageException {
    Struct meta;
   
    Document doc = CommonUtil.getDocument(clazz);
    Element cid = doc.createElement("composite-id");
    clazz.appendChild(cid);
   
    //cid.setAttribute("mapped","true");
   
   
    Property prop;
    // ids
    for(int y=0;y<props.length;y++){
      prop=props[y];
      meta = prop.getDynamicAttributes();
      Element key = doc.createElement("key-property");
      cid.appendChild(key);
     
      // name
      key.setAttribute("name",prop.getName());
     
      // column
      Element column = doc.createElement("column");
      key.appendChild(column);
     
      String str = toString(cfc,prop,meta,"column",data);
        if(Util.isEmpty(str,true)) str=prop.getName();
        column.setAttribute("name",formatColumn(str,data));
        ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,null);
       
            str = toString(cfc,prop,meta,"sqltype",data);
        if(!Util.isEmpty(str,true)) column.setAttribute("sql-type",str);
        str = toString(cfc,prop,meta,"length",data);
        if(!Util.isEmpty(str,true)) column.setAttribute("length",str);
           
        /*if(info!=null){
          column.setAttribute("sql-type",info.getTypeName());
          column.setAttribute("length",Caster.toString(info.getSize()));
        }*/
     
         // type
      //str=getType(info,prop,meta,"long"); //MUSTMUST
      //key.setAttribute("type", str);
     
      String generator=toString(cfc,prop,meta,"generator",data);
      String type = getType(info,cfc,prop,meta,getDefaultTypeForGenerator(generator,"string"),data);
      if(!Util.isEmpty(type))key.setAttribute("type", type);
     
     
     
           
    }
   
    // many-to-one
    String fieldType;
    for(int y=0;y<props.length;y++){
      prop=props[y];
      meta = prop.getDynamicAttributes();
      fieldType = toString(cfc,prop,meta,"fieldType",data);
      if(CommonUtil.listFindNoCaseIgnoreEmpty(fieldType,"many-to-one",',')==-1)continue;
     
      Element key = doc.createElement("key-many-to-one");
      cid.appendChild(key);
     
      // name
      key.setAttribute("name",prop.getName());
     
      // entity-name
      setForeignEntityName(cfc,prop, meta, key,false,data);
     
      // fkcolum
      String str=toString(cfc,prop,meta,"fkcolumn",data);
      setColumn(doc, key, str,data);
     
      // lazy
      setLazy(cfc,prop,meta,key,data);
    }
  }
 
 
  private static void createXMLMappingId(Component cfc,Element clazz, Property prop,Struct columnsInfo,String tableName,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
    String str;
   
    Document doc = CommonUtil.getDocument(clazz);
    Element id = doc.createElement("id");
    clazz.appendChild(id);
     
        // access
      str=toString(cfc,prop,meta,"access",data);
    if(!Util.isEmpty(str,true))id.setAttribute("access", str);
     
    // name
    id.setAttribute("name",prop.getName());
   
    // column
    Element column = doc.createElement("column");
    id.appendChild(column);

    str=toString(cfc,prop,meta,"column",data);
      if(Util.isEmpty(str,true)) str=prop.getName();
      column.setAttribute("name",formatColumn(str,data));
      ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,null);
      StringBuilder foreignCFC=new StringBuilder();
    String generator=createXMLMappingGenerator(id,cfc,prop,foreignCFC,data);

    str = toString(cfc,prop,meta,"length",data);
      if(!Util.isEmpty(str,true)) column.setAttribute("length",str);
       
    // type   
    String type = getType(info,cfc,prop,meta,getDefaultTypeForGenerator(generator,foreignCFC,data),data);
    //print.o(prop.getName()+":"+type+"::"+getDefaultTypeForGenerator(generator,foreignCFC));
    if(!Util.isEmpty(type))id.setAttribute("type", type);
   
    // unsaved-value
    str=toString(cfc,prop,meta,"unsavedValue",data);
    if(str!=null)id.setAttribute("unsaved-value", str);
   
  }
 
  private static String getDefaultTypeForGenerator(String generator,StringBuilder foreignCFC, SessionFactoryData data) {
    String value = getDefaultTypeForGenerator(generator, null);
    if(value!=null) return value;
   
    if("foreign".equalsIgnoreCase(generator)) {
      if(!Util.isEmpty(foreignCFC.toString())) {
        try {
          Component cfc = data.getEntityByCFCName(foreignCFC.toString(), false);
          if(cfc!=null){
            Property[] ids = getIds(cfc,cfc.getProperties(true),null,true,data);
            if(ids!=null && ids.length>0){
              Property id = ids[0];
              id.getDynamicAttributes();
              Struct meta = id.getDynamicAttributes();
              if(meta!=null){
                String type=CommonUtil.toString(meta.get(TYPE,null));
               
                if(!Util.isEmpty(type) && (!type.equalsIgnoreCase("any") && !type.equalsIgnoreCase("object"))){
                  return type;
                }
               
                  String g=CommonUtil.toString(meta.get(GENERATOR,null));
                  if(!Util.isEmpty(g)){
                    return getDefaultTypeForGenerator(g,foreignCFC,data);
                  }
               
              }
            }
          }
        }
        catch(Throwable t){}
      }
      return "string";
    }
   
    return "string";
  }
 
  private static String getDefaultTypeForGenerator(String generator,String defaultValue) {
    if("increment".equalsIgnoreCase(generator)) return "integer";
    if("identity".equalsIgnoreCase(generator)) return "integer";
    if("native".equalsIgnoreCase(generator)) return "integer";
    if("seqhilo".equalsIgnoreCase(generator)) return "string";
    if("uuid".equalsIgnoreCase(generator)) return "string";
    if("guid".equalsIgnoreCase(generator)) return "string";
    if("select".equalsIgnoreCase(generator)) return "string";
    return defaultValue;
  }
 
  private static String getType(ColumnInfo info, Component cfc,Property prop,Struct meta,String defaultValue, SessionFactoryData data) throws PageException {
    // ormType
    String type = toString(cfc,prop,meta,"ormType",data);
    //type=HibernateCaster.toHibernateType(info,type,null);
   
    // dataType
    if(Util.isEmpty(type,true)){
      type=toString(cfc,prop,meta,"dataType",data);
      //type=HibernateCaster.toHibernateType(info,type,null);
    }
   
    // type
    if(Util.isEmpty(type,true)){
      type=prop.getType();
      //type=HibernateCaster.toHibernateType(info,type,null);
    }
   
    // type from db info
    if(Util.isEmpty(type,true)){
      if(info!=null){
        type=info.getTypeName();
        //type=HibernateCaster.toHibernateType(info,type,defaultValue);
      }
      else return defaultValue;
    }
   
    return HibernateCaster.toHibernateType(info,type,defaultValue);
  }









  private static ColumnInfo getColumnInfo(Struct columnsInfo,String tableName,String columnName,ColumnInfo defaultValue) {
    if(columnsInfo!=null) {
        ColumnInfo info = (ColumnInfo) columnsInfo.get(CommonUtil.createKey(columnName),null);
      if(info==null) return defaultValue;
      return info;
      }
    return defaultValue;
  }
 
  /*private static ColumnInfo getColumnInfo(Struct columnsInfo,String tableName,String columnName,ORMEngine engine) throws PageException {
    if(columnsInfo!=null) {
        ColumnInfo info = (ColumnInfo) columnsInfo.get(columnName,null);
      if(info==null) {
        String msg="table ["+tableName+"] has no column with name ["+columnName+"]";
        if(columnsInfo!=null)
          msg+=", column names are ["+List.arrayToList(columnsInfo.keys(), ", ")+"]";
        ORMUtil.printError(msg, engine);
       
        //throw new ORMException(msg);
      }
      return info;
      }
    return null;
  }*/

  private static String createXMLMappingGenerator(Element id,Component cfc,Property prop,StringBuilder foreignCFC, SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
   
    // generator
    String className=toString(cfc,prop,meta,"generator",data);
    if(Util.isEmpty(className,true)) return null;
   

    Document doc = CommonUtil.getDocument(id);
    Element generator = doc.createElement("generator");
    id.appendChild(generator);
   
    generator.setAttribute("class", className);
   
    //print.e("generator:"+className);
   
    // params
    Object obj=meta.get(PARAMS,null);
    //if(obj!=null){
      Struct sct=null;
      if(obj==null) obj=CommonUtil.createStruct();
      else if(obj instanceof String) obj=ORMUtil.convertToSimpleMap((String)obj);
     
      if(CommonUtil.isStruct(obj)) sct=CommonUtil.toStruct(obj);
      else throw ExceptionUtil.createException(data,cfc,"invalid value for attribute [params] of tag [property]",null);
      className=className.trim().toLowerCase();
     
      // special classes
      if("foreign".equals(className)){
        if(!sct.containsKey(PROPERTY)) sct.setEL(PROPERTY, toString(cfc,prop,meta, PROPERTY,true,data));
       
        if(sct.containsKey(PROPERTY)){
          String p = CommonUtil.toString(sct.get(PROPERTY),null);
          if(!Util.isEmpty(p))foreignCFC.append(p);
        }
       
       
      }
      else if("select".equals(className)){
        //print.e("select:"+toString(meta, "selectKey",true));
        if(!sct.containsKey(KEY)) sct.setEL(KEY, toString(cfc,prop,meta, "selectKey",true,data));
      }
      else if("sequence".equals(className)){
        if(!sct.containsKey(SEQUENCE)) sct.setEL(SEQUENCE, toString(cfc,prop,meta, "sequence",true,data));
      }
     
      //Key[] keys = sct.keys();
      Iterator<Entry<Key, Object>> it = sct.entryIterator();
      Entry<Key, Object> e;
      Element param;
      while(it.hasNext()){
        e = it.next();
        param = doc.createElement("param");
        generator.appendChild(param);
       
        param.setAttribute( "name", e.getKey().getLowerString());
        param.appendChild(doc.createTextNode(CommonUtil.toString(e.getValue())));
       
      }
    //}
    return className;
  }
 
 
 
 

 

  private static void createXMLMappingProperty(Element clazz, PageContext pc,Component cfc,Property prop,Struct columnsInfo,String tableName,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
   
       
   
    // get table name
    String columnName=toString(cfc,prop,meta,"column",data);
      if(Util.isEmpty(columnName,true)) columnName=prop.getName();
     
      ColumnInfo info=getColumnInfo(columnsInfo,tableName,columnName,null);
   
    Document doc = CommonUtil.getDocument(clazz);
    final Element property = doc.createElement("property");
    clazz.appendChild(property);
   
    //name
    property.setAttribute("name",prop.getName());
   
    // type
    String str = getType(info, cfc,prop, meta, "string",data);
    property.setAttribute("type",str);
   
   
   
    // formula or column
    str=toString(cfc,prop,meta,"formula",data);
        Boolean b;
    if(!Util.isEmpty(str,true))  {
          property.setAttribute("formula","("+str+")");
        }
        else {
          //property.setAttribute("column",columnName);
         
          Element column = doc.createElement("column");
          property.appendChild(column);
          column.setAttribute("name", escape(HibernateUtil.convertColumnName(data,columnName)));

            // check
            str=toString(cfc,prop,meta,"check",data);
            if(!Util.isEmpty(str,true)) column.setAttribute("check",str);
           
          // default
          str=toString(cfc,prop,meta,"dbDefault",data);
          if(!Util.isEmpty(str,true)) column.setAttribute("default",str);
           
            // index
            str=toString(cfc,prop,meta,"index",data);
            if(!Util.isEmpty(str,true)) column.setAttribute("index",str);
         
          // length
            Integer i = toInteger(cfc,meta,"length",data);
            if(i!=null && i>0) column.setAttribute("length",CommonUtil.toString(i.intValue()));
           
            // not-null
            b=toBoolean(cfc,meta,"notnull",data);
            if(b!=null && b.booleanValue())column.setAttribute("not-null","true");
           
            // precision
            i=toInteger(cfc,meta,"precision",data);
            if(i!=null && i>-1) column.setAttribute("precision",CommonUtil.toString(i.intValue()));
           
            // scale
            i=toInteger(cfc,meta,"scale",data);
            if(i!=null && i>-1) column.setAttribute("scale",CommonUtil.toString(i.intValue()));
           
            // sql-type
            str=toString(cfc,prop,meta,"sqltype",data);
            if(!Util.isEmpty(str,true)) column.setAttribute("sql-type",str);
           
        // unique
            b=toBoolean(cfc,meta,"unique",data);
          if(b!=null && b.booleanValue())column.setAttribute("unique","true");
         
          // unique-key
          str=toString(cfc,prop,meta,"uniqueKey",data);
          if(Util.isEmpty(str))str=CommonUtil.toString(meta.get(UNIQUE_KEY_NAME,null),null);
          if(!Util.isEmpty(str,true)) column.setAttribute("unique-key",str);
         
         
        }
       
        // generated
        str=toString(cfc,prop,meta,"generated",data);
        if(!Util.isEmpty(str,true)){
          str=str.trim().toLowerCase();
         
          if("always".equals(str) || "insert".equals(str) || "never".equals(str))
            property.setAttribute("generated",str);
          else
            throw invalidValue(cfc,prop,"generated",str,"always,insert,never",data);
        //throw new ORMException("invalid value ["+str+"] for attribute [generated] of column ["+columnName+"], valid values are [always,insert,never]");
        }
       
       
        // update
        b=toBoolean(cfc,meta,"update",data);
        if(b!=null && !b.booleanValue())property.setAttribute("update","false");
       
        // insert
        b=toBoolean(cfc,meta,"insert",data);
        if(b!=null && !b.booleanValue())property.setAttribute("insert","false");
       
        // lazy (dtd defintion:<!ATTLIST property lazy (true|false) "false">)
        b=toBoolean(cfc,meta,"lazy",data);
        if(b!=null && b.booleanValue())property.setAttribute("lazy","true");
       
        // optimistic-lock
        b=toBoolean(cfc,meta,"optimisticlock",data);
        if(b!=null && !b.booleanValue())property.setAttribute("optimistic-lock","false");
       
  }
 
 
  /*
  MUST dies kommt aber nicht hier sondern in verarbeitung in component
  <cfproperty
    persistent="true|false"
   >
   * */
  private static void createXMLMappingOneToOne(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
   
    Boolean b;
   
    Document doc = CommonUtil.getDocument(clazz);
    Element x2o;
   
    // column
    String fkcolumn=toString(cfc,prop,meta,"fkcolumn",data);
    String linkTable=toString(cfc,prop,meta,"linkTable",data);
   
   
    if(!Util.isEmpty(linkTable,true) || !Util.isEmpty(fkcolumn,true)) {
      clazz=getJoin(clazz);
     
      x2o= doc.createElement("many-to-one");
      //x2o.setAttribute("column", fkcolumn);
      x2o.setAttribute("unique", "true");
     
      if(!Util.isEmpty(linkTable,true)){
        setColumn(doc, x2o, linkTable,data);
      }
      else {
        setColumn(doc, x2o, fkcolumn,data);
      }

     
     
     
      // update
          b=toBoolean(cfc,meta,"update",data);
          if(b!=null)x2o.setAttribute("update",CommonUtil.toString(b.booleanValue()));
         
          // insert
          b=toBoolean(cfc,meta,"insert",data);
          if(b!=null)x2o.setAttribute("insert",CommonUtil.toString(b.booleanValue()));
         
          // not-null
          b=toBoolean(cfc,meta,"notNull",data);
          if(b!=null)x2o.setAttribute("not-null",CommonUtil.toString(b.booleanValue()));
         
         
          // optimistic-lock
          b=toBoolean(cfc,meta,"optimisticLock",data);
          if(b!=null)x2o.setAttribute("optimistic-lock",CommonUtil.toString(b.booleanValue()));
         
          // not-found
      b=toBoolean(cfc,meta, "missingRowIgnored",data);
          if(b!=null && b.booleanValue()) x2o.setAttribute("not-found", "ignore");

      /* / index
      str=toString(meta,"index");
      if(!Util.isEmpty(str,true)) x2o.setAttribute("index", str);
      */
     
     
    }
    else {
      x2o= doc.createElement("one-to-one");
    }
    clazz.appendChild(x2o);
   
    // access
    String str=toString(cfc,prop,meta,"access",data);
    if(!Util.isEmpty(str,true)) x2o.setAttribute("access", str);
     
    // constrained
    b=toBoolean(cfc,meta, "constrained",data);
        if(b!=null && b.booleanValue()) x2o.setAttribute("constrained", "true");
   
    // formula
    str=toString(cfc,prop,meta,"formula",data);
    if(!Util.isEmpty(str,true)) x2o.setAttribute("formula", str);
   
    // embed-xml
    str=toString(cfc,prop,meta,"embedXml",data);
    if(!Util.isEmpty(str,true)) x2o.setAttribute("embed-xml", str);
   
    // property-ref
    str=toString(cfc,prop,meta,"mappedBy",data);
    if(!Util.isEmpty(str,true)) x2o.setAttribute("property-ref", str);
   
    // foreign-key
    str=toString(cfc,prop,meta,"foreignKeyName",data);
    if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data);
    if(!Util.isEmpty(str,true)) x2o.setAttribute("foreign-key", str);
       
    setForeignEntityName(cfc,prop,meta,x2o,true,data);
   
    createXMLMappingXToX(x2o, pc,cfc,prop,meta,data);
  }
 
 
 
 
 
 
  private static Component loadForeignCFC(PageContext pc,Component cfc,Property prop, Struct meta, SessionFactoryData data) throws PageException {
    // entity
    String str=toString(cfc,prop,meta,"entityName",data);
    Component fcfc=null;
   
    if(!Util.isEmpty(str,true)) {
      fcfc = data.getEntityByEntityName(str, false);
      if(fcfc!=null) return fcfc;
    }
     
    str = toString(cfc,prop,meta,"cfc",false,data);
    if(!Util.isEmpty(str,true)){
      return data.getEntityByCFCName(str, false);
    }
    return null;
  }









  private static void createXMLMappingCollection(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
    Document doc = CommonUtil.getDocument(clazz);
    Element el=null;
           
    // collection type
    String str=prop.getType();
    if(Util.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array";
    else str=str.trim().toLowerCase();
   
   
   
    // bag
    if("array".equals(str) || "bag".equals(str)){
      el = doc.createElement("bag");
    }
    // map
    else if("struct".equals(str) || "map".equals(str)){
      el = doc.createElement("map");
     
     
      // map-key
      str=toString(cfc,prop,meta,"structKeyColumn",true,data);
      if(!Util.isEmpty(str,true)) {
        Element mapKey=doc.createElement("map-key");
        el.appendChild(mapKey);
        mapKey.setAttribute("column", str);
       
        // type
        str=toString(cfc,prop,meta,"structKeyType",data);
        if(!Util.isEmpty(str,true))mapKey.setAttribute("type", str);
        else mapKey.setAttribute("type", "string");
      }
    }
    else throw invalidValue(cfc,prop,"collectiontype",str,"array,struct",data);
    //throw new ORMException("invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]");
   
    setBeforeJoin(clazz,el);
   
    // name
    el.setAttribute("name", prop.getName());
   
    // table
    str=toString(cfc,prop,meta, "table",true,data);
    el.setAttribute("table",escape(HibernateUtil.convertTableName(data,str)));
   
    // catalog
    str=toString(cfc,prop,meta, "catalog",data);
    if(!Util.isEmpty(str,true))el.setAttribute("catalog",str);
   
    // schema
    str=toString(cfc,prop,meta, "schema",data);
    if(!Util.isEmpty(str,true))el.setAttribute("schema",str);
   
    // mutable
    Boolean b=toBoolean(cfc,meta, "readonly",data);
        if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false");
   
    // order-by
    str=toString(cfc,prop,meta, "orderby",data);
    if(!Util.isEmpty(str,true))el.setAttribute("order-by",str);
   
    // element-column
    str=toString(cfc,prop,meta,"elementcolumn",data);
    if(!Util.isEmpty(str,true)){
      Element element = doc.createElement("element");
      el.appendChild(element);
     
      // column
      element.setAttribute("column", formatColumn(str,data));
     
      // type
      str=toString(cfc,prop,meta,"elementtype",data);
      if(!Util.isEmpty(str,true)) element.setAttribute("type", str);
    }
   
        // batch-size
        Integer i=toInteger(cfc,meta, "batchsize",data);
        if(i!=null && i.intValue()>1) el.setAttribute("batch-size", CommonUtil.toString(i.intValue()));
    // column
    str=toString(cfc,prop,meta,"fkcolumn",data);
    if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"column",data);
    if(!Util.isEmpty(str,true)){
      Element key = doc.createElement("key");
      CommonUtil.setFirst(el,key);
      //el.appendChild(key);
     
      // column
      key.setAttribute("column", formatColumn(str,data));
     
      // property-ref
      str=toString(cfc,prop,meta,"mappedBy",data);
      if(!Util.isEmpty(str,true)) key.setAttribute("property-ref", str);
    }
   
    // cache
    setCacheStrategy(cfc,prop,doc, meta, el,data);
   
    // optimistic-lock
    b=toBoolean(cfc,meta, "optimisticlock",data);
        if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false");
       
      
  }
 
 
  private static void setBeforeJoin(Element clazz, Element el) {
    Element join;
    if(clazz.getNodeName().equals("join")) {
      join=clazz;
      clazz = getClazz(clazz);
    }
    else {
      join = getJoin(clazz);
    }
   
    if(join==clazz) clazz.appendChild(el);
    else clazz.insertBefore(el, join);
   
   
  }
 
  private static Element getClazz(Element join) {
    if(join.getNodeName().equals("join")){
      return (Element) join.getParentNode();
    }
    return join;
  }

  private static Element getJoin(Element clazz) {
    if(clazz.getNodeName().equals("subclass")){
      NodeList joins = clazz.getElementsByTagName("join");
      if(joins!=null && joins.getLength()>0)
        return (Element)joins.item(0);
    }
    return clazz;
  }












  private static void createXMLMappingManyToMany(Component cfc,PropertyCollection propColl,Element clazz, PageContext pc,Property prop,DatasourceConnection dc, SessionFactoryData data) throws PageException {
    Element el = createXMLMappingXToMany(propColl,clazz, pc, cfc,prop,data);
    Struct meta = prop.getDynamicAttributes();
    Document doc = CommonUtil.getDocument(clazz);
    Element m2m = doc.createElement("many-to-many");
    el.appendChild(m2m);
   
    // link
    setLink(cfc,prop,el,meta,true,data);
   
    setForeignEntityName(cfc,prop, meta, m2m,true,data);

        // order-by
    String str = toString(cfc,prop,meta,"orderby",data);
    if(!Util.isEmpty(str,true))m2m.setAttribute("order-by", str);
   
    // column
    str=toString(cfc,prop,meta,"inversejoincolumn",data);
   
    // build fkcolumn name
    if(Util.isEmpty(str,true)) {
      Component other = loadForeignCFC(pc, cfc, prop, meta,data);
      if(other!=null){
        boolean isClass=Util.isEmpty(other.getExtends());
        // MZ: Recursive search for persistent mappedSuperclass properties
        Property[] _props=getProperties(pc,other,dc,meta,isClass, true,data);
        PropertyCollection _propColl = splitJoins(cfc,new HashMap<String, PropertyCollection>(), _props,data);
        _props=_propColl.getProperties();
       
        Struct m;
        Property _prop=null;
        for(int i=0;i<_props.length;i++){
          m = _props[i].getDynamicAttributes();
          // fieldtype
          String fieldtype = CommonUtil.toString(m.get(FIELDTYPE,null),null);
          if("many-to-many".equalsIgnoreCase(fieldtype)) {
            // linktable
            String currLinkTable=CommonUtil.toString(meta.get(LINK_TABLE,null),null);
            String othLinkTable=CommonUtil.toString(m.get(LINK_TABLE,null),null);
            if(currLinkTable.equals(othLinkTable)) {
              // cfc name
              String cfcName=CommonUtil.toString(m.get(CFC,null),null);
              if(cfc.equalTo(cfcName)){
                _prop=_props[i];
              }
            }
          }
        }
        str=createM2MFKColumnName( other, _prop, _propColl,data);
      }
    }
    setColumn(doc, m2m, str,data);
   
    // not-found
    Boolean b=toBoolean(cfc,meta, "missingrowignored",data);
        if(b!=null && b.booleanValue()) m2m.setAttribute("not-found", "ignore");
       
        // property-ref
    str=toString(cfc,prop,meta,"mappedby",data);
    if(!Util.isEmpty(str,true)) m2m.setAttribute("property-ref", str);
   
    // foreign-key
    str=toString(cfc,prop,meta,"foreignKeyName",data);
    if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data);
    if(!Util.isEmpty(str,true)) m2m.setAttribute("foreign-key", str);
  }
 
  private static boolean setLink(Component cfc,Property prop,Element el, Struct meta, boolean linkTableRequired,SessionFactoryData data) throws PageException {
    String str=toString(cfc,prop,meta, "linktable",linkTableRequired,data);
   
   
    if(!Util.isEmpty(str,true)){

      el.setAttribute("table", escape(HibernateUtil.convertTableName(data,str)));
   
      // schema
      str=toString(cfc,prop,meta, "linkschema",data);
      if(Util.isEmpty(str,true)) str=data.getORMConfiguration().getSchema();
      if(!Util.isEmpty(str,true)) el.setAttribute("schema", str);
     
      // catalog
      str=toString(cfc,prop,meta, "linkcatalog",data);
      if(Util.isEmpty(str,true)) str=data.getORMConfiguration().getCatalog();
      if(!Util.isEmpty(str,true)) el.setAttribute("catalog", str);
      return true;
    }
    return false;
  }









  private static void createXMLMappingOneToMany(Component cfc,PropertyCollection propColl,Element clazz, PageContext pc,Property prop, SessionFactoryData data) throws PageException {
    Element el = createXMLMappingXToMany(propColl,clazz, pc, cfc,prop,data);
    Struct meta = prop.getDynamicAttributes();
    Document doc = CommonUtil.getDocument(clazz);
    Element x2m;
   
   
        // order-by
    String str = toString(cfc,prop,meta,"orderby",data);
    if(!Util.isEmpty(str,true))el.setAttribute("order-by", str);
   
    // link
    if(setLink(cfc,prop,el,meta,false,data)){
      x2m = doc.createElement("many-to-many");
      x2m.setAttribute("unique","true");
     
      str=toString(cfc,prop,meta,"inversejoincolumn",data);
      setColumn(doc, x2m, str,data);
    }
    else {
      x2m = doc.createElement("one-to-many");
    }
    el.appendChild(x2m);
   

    // entity-name
   
    setForeignEntityName(cfc,prop,meta,x2m,true,data);
   
  }

 

 
 
 
 
 
  private static Element createXMLMappingXToMany(PropertyCollection propColl,Element clazz, PageContext pc,Component cfc,Property prop, SessionFactoryData data) throws PageException {
    final Struct meta = prop.getDynamicAttributes();
    Document doc = CommonUtil.getDocument(clazz);
    Element el=null;
   
   
   
  // collection type
    String str=prop.getType();
    if(Util.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array";
    else str=str.trim().toLowerCase();
   
    Element mapKey=null;
    // bag
    if("array".equals(str) || "bag".equals(str)){
      el = doc.createElement("bag");
     
    }
    // map
    else if("struct".equals(str) || "map".equals(str)){
      el = doc.createElement("map");
     
      // map-key
      mapKey = doc.createElement("map-key");
      //el.appendChild(mapKey);
     
      // column
      str=toString(cfc,prop,meta,"structKeyColumn",true,data);
      mapKey.setAttribute("column", formatColumn(str,data));
     
      // type
      str=toString(cfc,prop,meta,"structKeyType",data);
      if(!Util.isEmpty(str,true))mapKey.setAttribute("type", str);
      else mapKey.setAttribute("type", "string");// MUST get type dynamicly
    }
    else throw invalidValue(cfc,prop,"collectiontype",str,"array,struct",data);
    //throw new ORMException("invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]");
   
    setBeforeJoin(clazz,el);
   

   
    // batch-size
        Integer i=toInteger(cfc,meta, "batchsize",data);
        if(i!=null){
          if(i.intValue()>1) el.setAttribute("batch-size", CommonUtil.toString(i.intValue()));
        }
    // cacheUse
        setCacheStrategy(cfc,prop,doc, meta, el,data);
       
        // column
        str=createFKColumnName(cfc,prop,propColl,data);
   
    if(!Util.isEmpty(str,true)){
      Element key = doc.createElement("key");
      el.appendChild(key);
     
      // column
      setColumn(doc,key,str,data);
     
      // property-ref
      str=toString(cfc,prop,meta,"mappedBy",data);
      if(!Util.isEmpty(str,true)) key.setAttribute("property-ref", str);
    }
   
        // inverse
    Boolean b = toBoolean(cfc,meta, "inverse",data);
        if(b!=null && b.booleanValue()) el.setAttribute("inverse", "true");
       
   
   
    // mutable
    b = toBoolean(cfc,meta, "readonly",data);
        if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false");
   
    // optimistic-lock
    b=toBoolean(cfc,meta, "optimisticlock",data);
        if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false");
       
    // where
    str=toString(cfc,prop,meta,"where",data);
    if(!Util.isEmpty(str,true)) el.setAttribute("where", str);
       
    // add map key
        if(mapKey!=null)el.appendChild(mapKey);
       
       
    createXMLMappingXToX(el, pc,cfc,prop,meta,data);
   
    return el;
  }
 
 
 
  private static String createFKColumnName(Component cfc, Property prop, PropertyCollection propColl, SessionFactoryData data) throws PageException {
   
   
    // fk column from local defintion
    String str=prop==null?null:toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",data);
    if(!Util.isEmpty(str))
      return str;
   
    // no local defintion, get from Foreign enity
    Struct meta = prop.getDynamicAttributes();
    String type=toString(cfc,prop,meta,"fieldtype",false,data);
    String otherType;
    if("many-to-one".equalsIgnoreCase(type))     otherType="one-to-many";
    else if("one-to-many".equalsIgnoreCase(type))   otherType="many-to-one";
    else return createM2MFKColumnName( cfc, prop, propColl,data);
   
    String feName = toString(cfc,prop,meta,"cfc",true,data);
    Component feCFC=data.getEntityByCFCName(feName, false);
    Property[] feProps = feCFC.getProperties(true);
   
    Property p;
    Component _cfc;
    for(int i=0;i<feProps.length;i++){
      p=feProps[i];

      // compare fieldType
      str=toString(feCFC,p,p.getDynamicAttributes(),"fieldtype",false,data);
      if(!otherType.equalsIgnoreCase(str)) continue;
     
      // compare cfc
      str=toString(feCFC,p,p.getDynamicAttributes(),"cfc",false,data);
      if(Util.isEmpty(str)) continue;
      _cfc=data.getEntityByCFCName(str, false);
      if(_cfc==null || !_cfc.equals(cfc))continue;
     
      // get fkcolumn
      str=toString(_cfc,p,p.getDynamicAttributes(),"fkcolumn",data);
      if(!Util.isEmpty(str)) return str;
     
     
    }
    throw ExceptionUtil.createException(data,null,"cannot terminate foreign key column name for component "+cfc.getName(),null);
  }
 
 
  private static String createM2MFKColumnName(Component cfc, Property prop, PropertyCollection propColl,SessionFactoryData data) throws PageException {
   
    String str=prop==null?null:toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",data);
    if(Util.isEmpty(str)){
      Property[] ids = getIds(cfc,propColl,data);
      if(ids.length==1) {
        str=toString(cfc,ids[0],ids[0].getDynamicAttributes(),"column",data);
          if(Util.isEmpty(str,true)) str=ids[0].getName();
      }
      else if(prop!=null)str=toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",true,data);
      else
        throw ExceptionUtil.createException(data,null,"cannot terminate foreign key column name for component "+cfc.getName(),null);
     
      str=HibernateCaster.getEntityName(cfc)+"_"+str;
    }
      return str;
  }

  private static void setForeignEntityName(Component cfc,Property prop, Struct meta, Element el, boolean cfcRequired, SessionFactoryData data) throws PageException {
    // entity
    String str=cfcRequired?null:toString(cfc,prop,meta,"entityName",data);
    if(!Util.isEmpty(str,true)) {
      el.setAttribute("entity-name", str);
    }
    else {
      // cfc
      //createFKColumnName( cfc, prop, propColl);
     
      str = toString(cfc,prop,meta,"cfc",cfcRequired,data);
      if(!Util.isEmpty(str,true)){
        Component _cfc=data.getEntityByCFCName(str, false);
        str=HibernateCaster.getEntityName(_cfc);
        el.setAttribute("entity-name", str);
      }
    }
  }









  private static void setCacheStrategy(Component cfc,Property prop,Document doc,Struct meta, Element el, SessionFactoryData data) throws PageException {
    String strategy = toString(cfc,prop,meta,"cacheuse",data);
   
    if(!Util.isEmpty(strategy,true)){
      strategy=strategy.trim().toLowerCase();
      if("read-only".equals(strategy) || "nonstrict-read-write".equals(strategy) || "read-write".equals(strategy) || "transactional".equals(strategy)){
        Element cache = doc.createElement("cache");
        CommonUtil.setFirst(el, cache);
        el.appendChild(cache);
        cache.setAttribute("usage", strategy);
        String name = toString(cfc,prop,meta,"cacheName",data);
        if(!Util.isEmpty(name,true)){
          cache.setAttribute("region", name);
        }
      } 
      else
        throw ExceptionUtil.createException(data,cfc,"invalid value ["+strategy+"] for attribute [cacheuse], valid values are [read-only,nonstrict-read-write,read-write,transactional]",null);
    }
   
  }

 





  private static void setColumn(Document doc, Element el, String columnValue,SessionFactoryData data) throws PageException {
    if(Util.isEmpty(columnValue,true)) return;
   
    String[] arr = CommonUtil.toStringArray(columnValue, ',');
    if(arr.length==1){
      el.setAttribute("column", formatColumn(arr[0],data));
    }
    else {
      Element column;
      for(int i=0;i<arr.length;i++){
        column=doc.createElement("column");
        el.appendChild(column);
        column.setAttribute("name", formatColumn(arr[i],data));
      }
    }
  }









  private static void createXMLMappingManyToOne(Element clazz, PageContext pc,Component cfc,Property prop, PropertyCollection propColl, SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
    Boolean b;
   
    Document doc = CommonUtil.getDocument(clazz);
    clazz=getJoin(clazz);
   
    Element m2o = doc.createElement("many-to-one");
    clazz.appendChild(m2o);
   
    // columns
    String linktable = toString(cfc,prop,meta,"linktable",data);
    String _columns;
    if(!Util.isEmpty(linktable,true)) _columns=toString(cfc,prop,meta,"inversejoincolumn",data);
    else _columns=createFKColumnName(cfc, prop, propColl,data);//toString(cfc,prop,meta,"fkcolumn");
    setColumn(doc, m2o, _columns,data);
   
    // cfc
    setForeignEntityName(cfc,prop,meta,m2o,true,data);
   
    // column
    //String str=toString(prop,meta,"column",true);
    //m2o.setAttribute("column", str);
   
    // insert
    b=toBoolean(cfc,meta, "insert",data);
        if(b!=null && !b.booleanValue()) m2o.setAttribute("insert", "false");
   
        // update
    b=toBoolean(cfc,meta, "update",data);
        if(b!=null && !b.booleanValue()) m2o.setAttribute("update", "false");
   
        // property-ref
    String str=toString(cfc,prop,meta,"mappedBy",data);
    if(!Util.isEmpty(str,true)) m2o.setAttribute("property-ref", str);

        // update
    b=toBoolean(cfc,meta, "unique",data);
        if(b!=null && b.booleanValue()) m2o.setAttribute("unique", "true");

        // not-null
    b=toBoolean(cfc,meta, "notnull",data);
        if(b!=null && b.booleanValue()) m2o.setAttribute("not-null", "true");
   
        // optimistic-lock
    b=toBoolean(cfc,meta, "optimisticLock",data);
        if(b!=null && !b.booleanValue()) m2o.setAttribute("optimistic-lock", "false");
       
        // not-found
    b=toBoolean(cfc,meta, "missingRowIgnored",data);
        if(b!=null && b.booleanValue()) m2o.setAttribute("not-found", "ignore");
       
        // index
    str=toString(cfc,prop,meta,"index",data);
    if(!Util.isEmpty(str,true)) m2o.setAttribute("index", str);
       
        // unique-key
    str=toString(cfc,prop,meta,"uniqueKeyName",data);
    if(Util.isEmpty(str,true))str=toString(cfc,prop,meta,"uniqueKey",data);
    if(!Util.isEmpty(str,true)) m2o.setAttribute("unique-key", str);
   
    // foreign-key
    str=toString(cfc,prop,meta,"foreignKeyName",data);
    if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data);
    if(!Util.isEmpty(str,true)) m2o.setAttribute("foreign-key", str);

    // access
    str=toString(cfc,prop,meta,"access",data);
    if(!Util.isEmpty(str,true)) m2o.setAttribute("access", str);
   
        createXMLMappingXToX(m2o, pc,cfc,prop,meta,data);
       
  }
 
 
 
 
 
 
 
 
  private static String formatColumn(String name,SessionFactoryData data) throws PageException {
        name=name.trim();
    return escape(HibernateUtil.convertColumnName(data,name));
    }
 
  /*

  <cfproperty
cfc="Referenced_CFC_Name"
linktable="Link table name"
linkcatalog="Catalog for the link table"
linkschema="Schema for the link table"
fkcolumn="Foreign Key column name"
inversejoincolumn="Column name or comma-separated list of primary key columns"


>

  */
  private static void createXMLMappingXToX(Element x2x, PageContext pc, Component cfc,Property prop, Struct meta, SessionFactoryData data) throws PageException {
    x2x.setAttribute("name",prop.getName());
   
    // cascade
    String str=toString(cfc,prop,meta,"cascade",data);
    if(!Util.isEmpty(str,true)) x2x.setAttribute("cascade", str);
   
    // fetch
    str=toString(cfc,prop,meta,"fetch",data);
    if(!Util.isEmpty(str,true)) {
      str=str.trim().toLowerCase();
      if("join".equals(str) || "select".equals(str))
        x2x.setAttribute("fetch", str);
      else
        throw invalidValue(cfc,prop,"fetch",str,"join,select",data);
      //throw new ORMException("invalid value ["+str+"] for attribute [fetch], valid values are [join,select]");
    }
   
    // lazy
    setLazy(cfc,prop,meta,x2x,data);
   
  }



 

  private static void setLazy(Component cfc,Property prop, Struct meta, Element x2x, SessionFactoryData data) throws PageException {
    String str = toString(cfc,prop,meta, "lazy",data);
    if(!Util.isEmpty(str,true)){
      str=str.trim();
      String name=x2x.getNodeName();
      Boolean b = CommonUtil.toBoolean(str,null);
     
      // <!ATTLIST many-to-one lazy (false|proxy|no-proxy) #IMPLIED>
      // <!ATTLIST one-to-one lazy (false|proxy|no-proxy) #IMPLIED>
      if("many-to-one".equals(name) || "one-to-one".equals(name)) {
        if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false");
        else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy");
        else if("no-proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "no-proxy");
        else throw invalidValue(cfc,prop,"lazy",str,"true,false,proxy,no-proxy",data);
      }
     

      // <!ATTLIST many-to-many lazy (false|proxy) #IMPLIED>
      // <!ATTLIST key-many-to-one lazy (false|proxy) #IMPLIED>
      else if("many-to-many".equals(name) || "key-many-to-one".equals(name)) {
        if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false");
        else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy");
        throw invalidValue(cfc,prop,"lazy",str,"true,false,proxy",data);
       
      }
     
      else {
        if(b!=nullx2x.setAttribute("lazy", b.booleanValue()?"true":"false");
        else if("extra".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "extra");
        else  throw invalidValue(cfc,prop,"lazy",str,"true,false,extra",data);
      }
    }
  }

  private static void createXMLMappingTimestamp(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
    String str;
    Boolean b;
   

    Document doc = CommonUtil.getDocument(clazz);
    Element timestamp = doc.createElement("timestamp");
    clazz.appendChild(timestamp);
   
    timestamp.setAttribute("name",prop.getName());
   
     // access
    str=toString(cfc,prop,meta,"access",data);
    if(!Util.isEmpty(str,true))timestamp.setAttribute("access", str);
   
    // column
    str=toString(cfc,prop,meta,"column",data);
    if(Util.isEmpty(str,true)) str=prop.getName();
    timestamp.setAttribute("column",formatColumn(str,data));

    // generated
    b=toBoolean(cfc,meta, "generated",data);
        if(b!=null) timestamp.setAttribute("generated", b.booleanValue()?"always":"never");
       
        // source
        str=toString(cfc,prop,meta,"source",data);
    if(!Util.isEmpty(str,true)) {
      str=str.trim().toLowerCase();
      if("db".equals(str) || "vm".equals(str))
        timestamp.setAttribute("source", str);
      else
        throw invalidValue(cfc,prop,"source",str,"db,vm",data);
    }
   
    // unsavedValue
        str=toString(cfc,prop,meta,"unsavedValue",data);
    if(!Util.isEmpty(str,true)) {
      str=str.trim().toLowerCase();
      if("null".equals(str) || "undefined".equals(str))
        timestamp.setAttribute("unsaved-value", str);
      else
        throw invalidValue(cfc,prop,"unsavedValue",str,"null, undefined",data);
        //throw new ORMException("invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, undefined]");
    }
  }

 
  private static PageException invalidValue(Component cfc,Property prop, String attrName, String invalid, String valid, SessionFactoryData data) {
    String owner = prop.getOwnerName();
    if(Util.isEmpty(owner))return ExceptionUtil.createException(data,cfc,"invalid value ["+invalid+"] for attribute ["+attrName+"] of property ["+prop.getName()+"], valid values are ["+valid+"]",null);
    return ExceptionUtil.createException(data,cfc,"invalid value ["+invalid+"] for attribute ["+attrName+"] of property ["+prop.getName()+"] of Component ["+CommonUtil.last(owner,'.')+"], valid values are ["+valid+"]",null);
  }






  private static void createXMLMappingVersion(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException {
    Struct meta = prop.getDynamicAttributes();
   
    Document doc = CommonUtil.getDocument(clazz);
    Element version = doc.createElement("version");
    clazz.appendChild(version);
   
   
    version.setAttribute("name",prop.getName());
   
    // column
    String str = toString(cfc,prop,meta,"column",data);
    if(Util.isEmpty(str,true)) str=prop.getName();
    version.setAttribute("column",formatColumn(str,data));
   
     // access
      str=toString(cfc,prop,meta,"access",data);
    if(!Util.isEmpty(str,true))version.setAttribute("access", str);
   
    // generated
    Object o=meta.get(GENERATED,null);
    if(o!=null){
      Boolean b = CommonUtil.toBoolean(o,null);
      str=null;
      if(b!=null) {
        str=b.booleanValue()?"always":"never";
      }
      else {
        str=CommonUtil.toString(o,null);
        if("always".equalsIgnoreCase(str))str="always";
        else if("never".equalsIgnoreCase(str))str="never";
        else throw invalidValue(cfc,prop,"generated",o.toString(),"true,false,always,never",data);
        //throw new ORMException("invalid value ["+o+"] for attribute [generated] of property ["+prop.getName()+"], valid values are [true,false,always,never]");
      }
      version.setAttribute( "generated", str);
    }
   
        // insert
        Boolean b = toBoolean(cfc,meta, "insert",data);
        if(b!=null && !b.booleanValue()) version.setAttribute("insert", "false");
       
        // type
        String typeName="dataType";
    str=toString(cfc,prop,meta,typeName,data);
    if(Util.isEmpty(str,true)){
      typeName="ormType";
      str=toString(cfc,prop,meta,typeName,data);
    }
    if(!Util.isEmpty(str,true)) {
      str=str.trim().toLowerCase();
      if("int".equals(str) || "integer".equals(str))
        version.setAttribute("type", "integer");
      else if("long".equals(str))
        version.setAttribute("type", "long");
      else if("short".equals(str))
        version.setAttribute("type", "short");
      else
        throw invalidValue(cfc,prop,typeName,str,"int,integer,long,short",data);
      //throw new ORMException("invalid value ["+str+"] for attribute ["+typeName+"], valid values are [int,integer,long,short]");
    }
    else
      version.setAttribute("type", "integer");
   
    // unsavedValue
        str=toString(cfc,prop,meta,"unsavedValue",data);
    if(!Util.isEmpty(str,true)) {
      str=str.trim().toLowerCase();
      if("null".equals(str) || "negative".equals(str) || "undefined".equals(str))
        version.setAttribute("unsaved-value", str);
      else
        throw invalidValue(cfc,prop,"unsavedValue",str,"null, negative, undefined",data);
      //throw new ORMException("invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, negative, undefined]");
    }
  }  
 
  private static String toString(Component cfc,Property prop,Struct sct, String key, SessionFactoryData data) throws PageException {
    return toString(cfc,prop,sct, key, false,data);
  }

  private static String toString(Component cfc,Property prop,Struct sct, String key, boolean throwErrorWhenNotExist, SessionFactoryData data) throws PageException {
    return toString(cfc,prop,sct, CommonUtil.createKey(key), throwErrorWhenNotExist,data);
  }
 
  private static String toString(Component cfc,Property prop,Struct sct, Collection.Key key, boolean throwErrorWhenNotExist, SessionFactoryData data) throws PageException {
    Object value = sct.get(key,null);
    if(value==null) {
      if(throwErrorWhenNotExist){
        if(prop==null)throw ExceptionUtil.createException(data,cfc,"attribute ["+key+"] is required",null);
        throw ExceptionUtil.createException(data,cfc,"attribute ["+key+"] of property ["+prop.getName()+"] of Component ["+_getCFCName(prop)+"] is required",null);
      }
      return null;
    }
   
    String str=CommonUtil.toString(value,null);
    if(str==null) {
      if(prop==null)
        throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a string",null);
      throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"] of property ["+prop.getName()+"] of Component ["+_getCFCName(prop)+"], value must be a string",null);
      }
    return str;
  }
 
  private static String _getCFCName(Property prop) {
    String owner = prop.getOwnerName();
    return CommonUtil.last(owner,'.');
  }
 
 
 
 
  private static Boolean toBoolean(Component cfc,Struct sct, String key, SessionFactoryData data) throws PageException {
    Object value = sct.get(CommonUtil.createKey(key),null);
    if(value==null) return null;
   
    Boolean b=CommonUtil.toBoolean(value,null);
    if(b==null) throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a boolean",null);
    return b;
  }

  private static Integer toInteger(Component cfc,Struct sct, String key,SessionFactoryData data) throws PageException {
    Object value = sct.get(CommonUtil.createKey(key),null);
    if(value==null) return null;
   
    Integer i=CommonUtil.toInteger(value,null);
    if(i==null) throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a numeric value",null);
    return i;
  }
 
 
}
 
  class PropertyCollection {
    private Property[] properties;
    private String tableName;
    public PropertyCollection(String tableName,Property[] properties) {
      this.tableName=tableName;
      this.properties=properties;
    }
    public PropertyCollection(String tableName, java.util.List<Property> properties) {
      this.tableName=tableName;
      this.properties=properties.toArray(new Property[properties.size()]);
    }
    public Property[] getProperties() {
      return properties;
    }
    public String getTableName() {
      return tableName;
    }

  }
TOP

Related Classes of railo.runtime.orm.hibernate.HBMCreator

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.