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.appendChild( clazz); 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.appendChild( clazz); } } } //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!=null) x2x.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; } }