001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.orm.hibernate; 020 021 022import java.util.ArrayList; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.Map; 026import java.util.Map.Entry; 027 028import lucee.loader.util.Util; 029import lucee.runtime.Component; 030import lucee.runtime.PageContext; 031import lucee.runtime.component.Property; 032import lucee.runtime.db.DatasourceConnection; 033import lucee.runtime.exp.PageException; 034import lucee.runtime.orm.ORMUtil; 035import lucee.runtime.type.Collection; 036import lucee.runtime.type.Collection.Key; 037import lucee.runtime.type.Struct; 038 039import org.w3c.dom.DOMException; 040import org.w3c.dom.Document; 041import org.w3c.dom.Element; 042import org.w3c.dom.NodeList; 043 044public class HBMCreator { 045 046 047 private static final Collection.Key PROPERTY = CommonUtil.createKey("property"); 048 private static final Collection.Key LINK_TABLE = CommonUtil.createKey("linktable"); 049 private static final Collection.Key CFC = CommonUtil.createKey("cfc"); 050 private static final Collection.Key GENERATOR = CommonUtil.createKey("generator"); 051 private static final Collection.Key PARAMS = CommonUtil.createKey("params"); 052 private static final Collection.Key SEQUENCE = CommonUtil.createKey("sequence"); 053 private static final Collection.Key UNIQUE_KEY_NAME = CommonUtil.createKey("uniqueKeyName"); 054 private static final Collection.Key GENERATED = CommonUtil.createKey("generated"); 055 private static final Collection.Key FIELDTYPE = CommonUtil.createKey("fieldtype"); 056 private static final Collection.Key KEY = CommonUtil.createKey("key"); 057 private static final Collection.Key TYPE = CommonUtil.createKey("type"); 058 059 public static void createXMLMapping(PageContext pc,DatasourceConnection dc, Component cfc,Element hibernateMapping,SessionFactoryData data) throws PageException { 060 061 // MUST Support for embeded objects 062 Struct meta = cfc.getMetaData(pc); 063 064 String extend = cfc.getExtends(); 065 boolean isClass=Util.isEmpty(extend); 066 067 // MZ: Fetches all inherited persistent properties 068 //Property[] _props=getAllPersistentProperties(pc,cfc,dc,meta,isClass); 069 070 Property[] _props=getProperties(pc,cfc,dc,meta,isClass, true,data); 071 072 073 074 Map<String, PropertyCollection> joins=new HashMap<String, PropertyCollection>(); 075 PropertyCollection propColl = splitJoins(cfc,joins, _props,data); 076 077 078 079 // create class element and attach 080 Document doc = CommonUtil.getDocument(hibernateMapping); 081 082 StringBuilder comment=new StringBuilder(); 083 comment.append("\nsource:").append(cfc.getPageSource().getDisplayPath()); 084 comment.append("\ncompilation-time:").append(CommonUtil.createDateTime(HibernateUtil.getCompileTime(pc,cfc.getPageSource()))); 085 comment.append("\ndatasource:").append(dc.getDatasource().getName()); 086 comment.append("\n"); 087 088 hibernateMapping.appendChild(doc.createComment(comment.toString())); 089 090 //print.e(cfc.getAbsName()+";"+isClass+" -> "+cfci.getBaseAbsName()+":"+cfci.isBasePeristent()); 091 if(!isClass && !cfc.isBasePeristent()) { 092 isClass=true; 093 } 094 095 096 Element join=null; 097 boolean doTable=true; 098 099 Element clazz; 100 if(isClass) { 101 clazz = doc.createElement("class"); 102 hibernateMapping.appendChild(clazz); 103 } 104 // extended CFC 105 else{ 106 // MZ: Fetches one level deep 107 _props=getProperties(pc,cfc,dc,meta,isClass, false,data); 108 // MZ: Reinitiate the property collection 109 propColl = splitJoins(cfc,joins, _props,data); 110 111 String ext = CommonUtil.last(extend,'.').trim(); 112 try { 113 Component base = data.getEntityByCFCName(ext, false); 114 ext = HibernateCaster.getEntityName(base); 115 } 116 catch(Throwable t){ 117 lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t); 118 } 119 120 121 String discriminatorValue = toString(cfc,null,meta,"discriminatorValue",data); 122 if(!Util.isEmpty(discriminatorValue,true)) { 123 doTable=false; 124 clazz = doc.createElement("subclass"); 125 hibernateMapping.appendChild(clazz); 126 //addClassAttributes(classNode); 127 clazz.setAttribute("extends", ext); 128 clazz.setAttribute("discriminator-value", discriminatorValue); 129 130 String joincolumn = toString(cfc,null,meta,"joincolumn",false,data); 131 if(!Util.isEmpty(joincolumn)){ 132 join = doc.createElement("join"); 133 clazz.appendChild(join); 134 doTable=true; 135 Element key = doc.createElement("key"); 136 join.appendChild(key); 137 key.setAttribute("column", formatColumn(joincolumn,data)); 138 } 139 140 } 141 else { 142 // MZ: Match on joinColumn for a joined subclass, otherwise use a union subclass 143 String joinColumn = toString(cfc,null,meta,"joincolumn",false,data); 144 if (!Util.isEmpty(joinColumn,true)) { 145 clazz = doc.createElement("joined-subclass"); 146 hibernateMapping.appendChild( clazz); 147 clazz.setAttribute("extends",ext); 148 Element key = doc.createElement("key"); 149 clazz.appendChild(key); 150 key.setAttribute("column", formatColumn(joinColumn,data)); 151 } 152 else { 153 // MZ: When no joinColumn exists, default to an explicit table per class 154 clazz = doc.createElement("union-subclass"); 155 clazz.setAttribute("extends",ext); 156 doTable = true; 157 hibernateMapping.appendChild( clazz); 158 } 159 160 } 161 } 162 163 //createXMLMappingTuplizer(clazz,pc); 164 165 addGeneralClassAttributes(pc,cfc,meta,clazz,data); 166 String tableName=getTableName(pc,meta,cfc,data); 167 168 if(join!=null) clazz=join; 169 if(doTable)addGeneralTableAttributes(pc,cfc,meta,clazz,data); 170 171 172 173 174 Struct columnsInfo=null; 175 if(data.getORMConfiguration().useDBForMapping()){ 176 columnsInfo = data.getTableInfo(dc,getTableName(pc, meta, cfc,data)); 177 } 178 179 if(isClass)setCacheStrategy(cfc,null,doc, meta, clazz,data); 180 181 // id 182 if(isClass) addId(cfc,doc,clazz,meta,propColl,columnsInfo,tableName,data); 183 184 // discriminator 185 if(isClass) addDiscriminator(cfc,doc,clazz,pc,meta,data); 186 187 // version 188 if(isClass)addVersion(cfc,clazz,pc, propColl,columnsInfo,tableName,data); 189 190 // property 191 addProperty(cfc,clazz,pc, propColl,columnsInfo,tableName,data); 192 193 // relations 194 addRelation(cfc,clazz,pc, propColl,columnsInfo,tableName,dc,data); 195 196 // collection 197 addCollection(cfc,clazz,pc, propColl,columnsInfo,tableName,data); 198 199 // join 200 addJoin(cfc,clazz,pc, joins,columnsInfo,tableName,dc,data); 201 202 203 } 204 205 private static Property[] getProperties(PageContext pc, Component cfc, DatasourceConnection dc, Struct meta, boolean isClass, boolean recursivePersistentMappedSuperclass,SessionFactoryData data) throws PageException, PageException { 206 Property[] _props; 207 if (recursivePersistentMappedSuperclass) { 208 _props = CommonUtil.getProperties(cfc,true, true, true, true); 209 } 210 else { 211 _props = cfc.getProperties(true); 212 } 213 214 if(isClass && _props.length==0 && data.getORMConfiguration().useDBForMapping()){ 215 if(meta==null)meta = cfc.getMetaData(pc); 216 _props=HibernateUtil.createPropertiesFromTable(dc,getTableName(pc, meta, cfc, data)); 217 } 218 return _props; 219 } 220 221 private static void addId(Component cfc,Document doc, Element clazz, Struct meta, PropertyCollection propColl, Struct columnsInfo, String tableName, SessionFactoryData data) throws PageException { 222 Property[] _ids = getIds(cfc,propColl,data); 223 224 //Property[] _ids = ids.toArray(new Property[ids.size()]); 225 226 if(_ids.length==1) 227 createXMLMappingId(cfc,clazz, _ids[0],columnsInfo,tableName,data); 228 else if(_ids.length>1) 229 createXMLMappingCompositeId(cfc,clazz, _ids,columnsInfo,tableName,data); 230 else 231 throw ExceptionUtil.createException(data,cfc,"missing id property for entity ["+HibernateCaster.getEntityName(cfc)+"]",null); 232 } 233 234 235 private static PropertyCollection splitJoins(Component cfc,Map<String, PropertyCollection> joins,Property[] props,SessionFactoryData data) { 236 Struct sct=CommonUtil.createStruct(); 237 ArrayList<Property> others = new ArrayList<Property>(); 238 java.util.List<Property> list; 239 String table; 240 Property prop; 241 String fieldType; 242 boolean isJoin; 243 for(int i=0;i<props.length;i++){ 244 prop=props[i]; 245 table=getTable(cfc,prop,data); 246 // joins 247 if(!Util.isEmpty(table,true)){ 248 isJoin=true; 249 // wrong field type 250 try { 251 fieldType = toString(cfc, prop, sct, FIELDTYPE,false,data); 252 253 if("collection".equalsIgnoreCase(fieldType)) isJoin=false; 254 else if("primary".equals(fieldType)) isJoin=false; 255 else if("version".equals(fieldType)) isJoin=false; 256 else if("timestamp".equals(fieldType)) isJoin=false; 257 } 258 catch (PageException e) {} 259 260 // missing column 261 String columns=null; 262 try { 263 if(ORMUtil.isRelated(props[i])){ 264 columns=toString(cfc,props[i], prop.getDynamicAttributes(), "fkcolumn",data); 265 } 266 else { 267 columns=toString(cfc,props[i], prop.getDynamicAttributes(), "joincolumn",data); 268 } 269 } 270 catch(PageException e){} 271 if(Util.isEmpty(columns)) isJoin=false; 272 273 if(isJoin){ 274 table=table.trim(); 275 list = (java.util.List<Property>) sct.get(table,null); 276 if(list==null){ 277 list=new ArrayList<Property>(); 278 sct.setEL(CommonUtil.createKey(table), list); 279 } 280 list.add(prop); 281 continue; 282 } 283 } 284 others.add(prop); 285 } 286 287 // fill to joins 288 Iterator<Entry<Key, Object>> it = sct.entryIterator(); 289 Entry<Key, Object> e; 290 while(it.hasNext()){ 291 e = it.next(); 292 list=(java.util.List<Property>) e.getValue(); 293 joins.put(e.getKey().getString(), new PropertyCollection(e.getKey().getString(),list)); 294 } 295 296 297 298 return new PropertyCollection(null,others); 299 } 300 301 302 303 304 305 private static Property[] getIds(Component cfc,PropertyCollection pc,SessionFactoryData data) { 306 return getIds(cfc,pc.getProperties(), pc.getTableName(),false,data); 307 } 308 309 private static Property[] getIds(Component cfc,Property[] props,String tableName, boolean ignoreTableName,SessionFactoryData data) { 310 ArrayList<Property> ids=new ArrayList<Property>(); 311 for(int y=0;y<props.length;y++){ 312 if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue; 313 314 315 String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null); 316 if("id".equalsIgnoreCase(fieldType) || CommonUtil.listFindNoCaseIgnoreEmpty(fieldType,"id",',')!=-1) 317 ids.add(props[y]); 318 } 319 320 // no id field defined 321 if(ids.size()==0) { 322 String fieldType; 323 for(int y=0;y<props.length;y++){ 324 if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue; 325 fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null); 326 if(Util.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase("id")){ 327 ids.add(props[y]); 328 props[y].getDynamicAttributes().setEL(FIELDTYPE, "id"); 329 } 330 } 331 } 332 333 // still no id field defined 334 if(ids.size()==0 && props.length>0) { 335 String owner = props[0].getOwnerName(); 336 if(!Util.isEmpty(owner)) owner=CommonUtil.last(owner, '.').trim(); 337 338 String fieldType; 339 if(!Util.isEmpty(owner)){ 340 String id=owner+"id"; 341 for(int y=0;y<props.length;y++){ 342 if(!ignoreTableName && !hasTable(cfc,props[y], tableName,data)) continue; 343 fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null); 344 if(Util.isEmpty(fieldType,true) && props[y].getName().equalsIgnoreCase(id)){ 345 ids.add(props[y]); 346 props[y].getDynamicAttributes().setEL(FIELDTYPE, "id"); 347 } 348 } 349 } 350 } 351 return ids.toArray(new Property[ids.size()]); 352 } 353 354 355 356 357 358 359 private static void addVersion(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,SessionFactoryData data) throws PageException { 360 Property[] props = propColl.getProperties(); 361 for(int y=0;y<props.length;y++){ 362 String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,null),null); 363 if("version".equalsIgnoreCase(fieldType)) 364 createXMLMappingVersion(clazz,pc, cfc,props[y],data); 365 else if("timestamp".equalsIgnoreCase(fieldType)) 366 createXMLMappingTimestamp(clazz,pc,cfc, props[y],data); 367 } 368 } 369 370 371 372 private static void addCollection(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName,SessionFactoryData data) throws PageException { 373 Property[] props = propColl.getProperties(); 374 for(int y=0;y<props.length;y++){ 375 String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column"); 376 if("collection".equalsIgnoreCase(fieldType)) 377 createXMLMappingCollection(clazz,pc, cfc,props[y],data); 378 } 379 } 380 381 382 private static void addJoin(Component cfc,Element clazz, PageContext pc,Map<String, PropertyCollection> joins, Struct columnsInfo, String tableName,DatasourceConnection dc, SessionFactoryData data) throws PageException { 383 384 Iterator<Entry<String, PropertyCollection>> it = joins.entrySet().iterator(); 385 Entry<String, PropertyCollection> entry; 386 while(it.hasNext()){ 387 entry = it.next(); 388 addJoin(cfc,pc,columnsInfo,clazz,entry.getValue(),dc,data); 389 } 390 391 392 393 } 394 395 private static void addJoin(Component cfc,PageContext pc,Struct columnsInfo, Element clazz, PropertyCollection coll, DatasourceConnection dc, SessionFactoryData data) throws PageException { 396 String table = coll.getTableName(); 397 Property[] properties = coll.getProperties(); 398 if(properties.length==0) return; 399 400 Document doc = CommonUtil.getDocument(clazz); 401 402 Element join = doc.createElement("join"); 403 clazz.appendChild(join); 404 405 join.setAttribute("table", escape(HibernateUtil.convertTableName(data,coll.getTableName()))); 406 //addTableInfo(joinNode, table, schema, catalog); 407 408 Property first = properties[0]; 409 String schema = null, catalog=null, mappedBy=null, columns=null; 410 if(ORMUtil.isRelated(first)){ 411 catalog=toString(cfc,first, first.getDynamicAttributes(), "linkcatalog",data); 412 schema=toString(cfc,first, first.getDynamicAttributes(), "linkschema",data); 413 columns=toString(cfc,first, first.getDynamicAttributes(), "fkcolumn",data); 414 415 } 416 else { 417 catalog=toString(cfc,first, first.getDynamicAttributes(), "catalog",data); 418 schema=toString(cfc,first, first.getDynamicAttributes(), "schema",data); 419 mappedBy=toString(cfc,first, first.getDynamicAttributes(), "mappedby",data); 420 columns=toString(cfc,first, first.getDynamicAttributes(), "joincolumn",data); 421 } 422 423 if(!Util.isEmpty(catalog)) join.setAttribute("catalog", catalog); 424 if(!Util.isEmpty(schema)) join.setAttribute("schema", schema); 425 426 Element key = doc.createElement("key"); 427 join.appendChild(key); 428 if(!Util.isEmpty(mappedBy)) key.setAttribute("property-ref", mappedBy); 429 setColumn(doc, key, columns,data); 430 431 addProperty(cfc,join,pc, coll,columnsInfo,table,data); 432 int count=addRelation(cfc,join,pc, coll,columnsInfo,table,dc,data); 433 434 if(count>0) join.setAttribute("inverse", "true"); 435 436 437 } 438 439 440 441 442 443 444 445 446 447 448 449 private static int addRelation(Component cfc,Element clazz, PageContext pc,PropertyCollection propColl, Struct columnsInfo, String tableName, DatasourceConnection dc, SessionFactoryData data) throws PageException { 450 Property[] props = propColl.getProperties(); 451 int count=0; 452 for(int y=0;y<props.length;y++){ 453 String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column"); 454 if("one-to-one".equalsIgnoreCase(fieldType)){ 455 createXMLMappingOneToOne(clazz,pc, cfc,props[y],data); 456 count++; 457 } 458 else if("many-to-one".equalsIgnoreCase(fieldType)){ 459 createXMLMappingManyToOne(clazz,pc, cfc,props[y],propColl,data); 460 count++; 461 } 462 else if("one-to-many".equalsIgnoreCase(fieldType)){ 463 createXMLMappingOneToMany(cfc,propColl,clazz,pc, props[y],data); 464 count++; 465 } 466 else if("many-to-many".equalsIgnoreCase(fieldType)){ 467 createXMLMappingManyToMany(cfc,propColl,clazz,pc, props[y],dc,data); 468 count++; 469 } 470 } 471 return count; 472 } 473 474 475 476 private static void addProperty(Component cfc,Element clazz, PageContext pc, PropertyCollection propColl, Struct columnsInfo, String tableName, SessionFactoryData data) throws PageException { 477 Property[] props = propColl.getProperties(); 478 for(int y=0;y<props.length;y++){ 479 String fieldType = CommonUtil.toString(props[y].getDynamicAttributes().get(FIELDTYPE,"column"),"column"); 480 if("column".equalsIgnoreCase(fieldType)) 481 createXMLMappingProperty(clazz,pc,cfc, props[y],columnsInfo,tableName,data); 482 } 483 } 484 485 486 487 private static void addDiscriminator(Component cfc,Document doc,Element clazz, PageContext pc,Struct meta,SessionFactoryData data) throws DOMException, PageException { 488 489 String str = toString(cfc,null,meta,"discriminatorColumn",data); 490 if(!Util.isEmpty(str,true)){ 491 Element disc = doc.createElement("discriminator"); 492 clazz.appendChild(disc); 493 disc.setAttribute("column",formatColumn(str,data)); 494 } 495 496 497 498 499 } 500 501 502 503 private static void addGeneralClassAttributes(PageContext pc, Component cfc, Struct meta, Element clazz, SessionFactoryData data) throws PageException { 504 505 // name 506 clazz.setAttribute("node", HibernateCaster.toComponentName(cfc)); 507 508 // entity-name 509 String str=toString(cfc,null,meta,"entityname",data); 510 if(Util.isEmpty(str,true)) str=HibernateCaster.getEntityName(cfc); 511 clazz.setAttribute("entity-name",str); 512 513 514 // batch-size 515 Integer i = toInteger(cfc,meta,"batchsize",data); 516 if(i!=null && i.intValue()>0)clazz.setAttribute("batch-size",CommonUtil.toString(i)); 517 518 // dynamic-insert 519 Boolean b = toBoolean(cfc,meta,"dynamicinsert",data); 520 if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-insert","true"); 521 522 // dynamic-update 523 b=toBoolean(cfc,meta,"dynamicupdate",data); 524 if(b!=null && b.booleanValue())clazz.setAttribute("dynamic-update","true"); 525 526 // lazy (dtd defintion:<!ATTLIST class lazy (true|false) #IMPLIED>) 527 b=toBoolean(cfc,meta,"lazy",data); 528 if(b==null) b=Boolean.TRUE; 529 clazz.setAttribute("lazy",CommonUtil.toString(b.booleanValue())); 530 531 // select-before-update 532 b=toBoolean(cfc,meta,"selectbeforeupdate",data); 533 if(b!=null && b.booleanValue())clazz.setAttribute("select-before-update","true"); 534 535 // optimistic-lock 536 str=toString(cfc,null,meta,"optimisticLock",data); 537 if(!Util.isEmpty(str,true)) { 538 str=str.trim().toLowerCase(); 539 if("all".equals(str) || "dirty".equals(str) || "none".equals(str) || "version".equals(str)) 540 clazz.setAttribute("optimistic-lock",str); 541 else 542 throw ExceptionUtil.createException(data,cfc,"invalid value ["+str+"] for attribute [optimisticlock] of tag [component], valid values are [all,dirty,none,version]",null); 543 } 544 545 // read-only 546 b=toBoolean(cfc,meta,"readOnly",data); 547 if(b!=null && b.booleanValue()) clazz.setAttribute("mutable", "false"); 548 549 // rowid 550 str=toString(cfc,null,meta,"rowid",data); 551 if(!Util.isEmpty(str,true)) clazz.setAttribute("rowid",str); 552 553 // where 554 str=toString(cfc,null,meta,"where",data); 555 if(!Util.isEmpty(str,true)) clazz.setAttribute("where", str); 556 557 558 } 559 private static void addGeneralTableAttributes(PageContext pc, Component cfc, Struct meta, Element clazz,SessionFactoryData data) throws PageException { 560 // table 561 clazz.setAttribute("table",escape(getTableName(pc,meta,cfc,data))); 562 563 // catalog 564 String str = toString(cfc,null,meta,"catalog",data); 565 if(str==null)// empty string is allowed as input 566 str=data.getORMConfiguration().getCatalog(); 567 if(!Util.isEmpty(str,true)) clazz.setAttribute("catalog", str); 568 569 // schema 570 str=toString(cfc,null,meta,"schema",data); 571 if(str==null)// empty string is allowed as input 572 str=data.getORMConfiguration().getSchema(); 573 if(!Util.isEmpty(str,true)) clazz.setAttribute( "schema", str); 574 575 } 576 private static String escape(String str) { 577 if(HibernateUtil.isKeyword(str)) return "`"+str+"`"; 578 return str; 579 } 580 581 582 583 584 585 586 private static String getTableName(PageContext pc, Struct meta, Component cfc,SessionFactoryData data) throws PageException { 587 String tableName=toString(cfc,null,meta,"table",data); 588 if(Util.isEmpty(tableName,true)) 589 tableName=HibernateCaster.getEntityName(cfc); 590 return HibernateUtil.convertTableName(data,tableName); 591 } 592 593 private static String getTable(Component cfc,Property prop,SessionFactoryData data) { 594 try { 595 return HibernateUtil.convertTableName(data,toString(cfc,prop, prop.getDynamicAttributes(), "table",data)); 596 } catch (PageException e) { 597 return null; 598 } 599 } 600 601 private static boolean hasTable(Component cfc,Property prop,String tableName,SessionFactoryData data) { 602 String t = getTable(cfc,prop,data); 603 boolean left=Util.isEmpty(t,true); 604 boolean right=Util.isEmpty(tableName,true); 605 if(left && right) return true; 606 if(left || right) return false; 607 return tableName.trim().equalsIgnoreCase(t.trim()); 608 } 609 610 611 612 613 614 615 private static void createXMLMappingCompositeId(Component cfc,Element clazz, Property[] props,Struct columnsInfo,String tableName, SessionFactoryData data) throws PageException { 616 Struct meta; 617 618 Document doc = CommonUtil.getDocument(clazz); 619 Element cid = doc.createElement("composite-id"); 620 clazz.appendChild(cid); 621 622 //cid.setAttribute("mapped","true"); 623 624 625 Property prop; 626 String fieldType; 627 // ids 628 for(int y=0;y<props.length;y++){ 629 prop=props[y]; 630 631 632 // do not add "key-property" for many-to-one 633 meta = prop.getDynamicAttributes(); 634 fieldType = toString(cfc,prop,meta,"fieldType",data); 635 if(CommonUtil.listFindNoCaseIgnoreEmpty(fieldType,"many-to-one",',')!=-1)continue; 636 637 638 Element key = doc.createElement("key-property"); 639 cid.appendChild(key); 640 641 // name 642 key.setAttribute("name",prop.getName()); 643 644 // column 645 Element column = doc.createElement("column"); 646 key.appendChild(column); 647 648 String str = toString(cfc,prop,meta,"column",data); 649 if(Util.isEmpty(str,true)) str=prop.getName(); 650 column.setAttribute("name",formatColumn(str,data)); 651 ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,null); 652 653 str = toString(cfc,prop,meta,"sqltype",data); 654 if(!Util.isEmpty(str,true)) column.setAttribute("sql-type",str); 655 str = toString(cfc,prop,meta,"length",data); 656 if(!Util.isEmpty(str,true)) column.setAttribute("length",str); 657 658 String generator=toString(cfc,prop,meta,"generator",data); 659 String type = getType(info,cfc,prop,meta,getDefaultTypeForGenerator(generator,"string"),data); 660 if(!Util.isEmpty(type))key.setAttribute("type", type); 661 } 662 663 // many-to-one 664 for(int y=0;y<props.length;y++){ 665 prop=props[y]; 666 meta = prop.getDynamicAttributes(); 667 fieldType = toString(cfc,prop,meta,"fieldType",data); 668 if(CommonUtil.listFindNoCaseIgnoreEmpty(fieldType,"many-to-one",',')==-1)continue; 669 670 Element key = doc.createElement("key-many-to-one"); 671 cid.appendChild(key); 672 673 // name 674 key.setAttribute("name",prop.getName()); 675 676 // entity-name 677 setForeignEntityName(cfc,prop, meta, key,false,data); 678 679 // fkcolum 680 String str=toString(cfc,prop,meta,"fkcolumn",data); 681 setColumn(doc, key, str,data); 682 683 // lazy 684 setLazy(cfc,prop,meta,key,data); 685 } 686 } 687 688 689 private static void createXMLMappingId(Component cfc,Element clazz, Property prop,Struct columnsInfo,String tableName,SessionFactoryData data) throws PageException { 690 Struct meta = prop.getDynamicAttributes(); 691 String str; 692 693 Document doc = CommonUtil.getDocument(clazz); 694 Element id = doc.createElement("id"); 695 clazz.appendChild(id); 696 697 // access 698 str=toString(cfc,prop,meta,"access",data); 699 if(!Util.isEmpty(str,true))id.setAttribute("access", str); 700 701 // name 702 id.setAttribute("name",prop.getName()); 703 704 // column 705 Element column = doc.createElement("column"); 706 id.appendChild(column); 707 708 str=toString(cfc,prop,meta,"column",data); 709 if(Util.isEmpty(str,true)) str=prop.getName(); 710 column.setAttribute("name",formatColumn(str,data)); 711 ColumnInfo info=getColumnInfo(columnsInfo,tableName,str,null); 712 StringBuilder foreignCFC=new StringBuilder(); 713 String generator=createXMLMappingGenerator(id,cfc,prop,foreignCFC,data); 714 715 str = toString(cfc,prop,meta,"length",data); 716 if(!Util.isEmpty(str,true)) column.setAttribute("length",str); 717 718 // type 719 String type = getType(info,cfc,prop,meta,getDefaultTypeForGenerator(generator,foreignCFC,data),data); 720 //print.o(prop.getName()+":"+type+"::"+getDefaultTypeForGenerator(generator,foreignCFC)); 721 if(!Util.isEmpty(type))id.setAttribute("type", type); 722 723 // unsaved-value 724 str=toString(cfc,prop,meta,"unsavedValue",data); 725 if(str!=null)id.setAttribute("unsaved-value", str); 726 727 } 728 729 private static String getDefaultTypeForGenerator(String generator,StringBuilder foreignCFC, SessionFactoryData data) { 730 String value = getDefaultTypeForGenerator(generator, null); 731 if(value!=null) return value; 732 733 if("foreign".equalsIgnoreCase(generator)) { 734 if(!Util.isEmpty(foreignCFC.toString())) { 735 try { 736 Component cfc = data.getEntityByCFCName(foreignCFC.toString(), false); 737 if(cfc!=null){ 738 Property[] ids = getIds(cfc,cfc.getProperties(true),null,true,data); 739 if(ids!=null && ids.length>0){ 740 Property id = ids[0]; 741 id.getDynamicAttributes(); 742 Struct meta = id.getDynamicAttributes(); 743 if(meta!=null){ 744 String type=CommonUtil.toString(meta.get(TYPE,null)); 745 746 if(!Util.isEmpty(type) && (!type.equalsIgnoreCase("any") && !type.equalsIgnoreCase("object"))){ 747 return type; 748 } 749 750 String g=CommonUtil.toString(meta.get(GENERATOR,null)); 751 if(!Util.isEmpty(g)){ 752 return getDefaultTypeForGenerator(g,foreignCFC,data); 753 } 754 755 } 756 } 757 } 758 } 759 catch(Throwable t){ 760 lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t); 761 } 762 } 763 return "string"; 764 } 765 766 return "string"; 767 } 768 769 public static String getDefaultTypeForGenerator(String generator,String defaultValue) { 770 if("increment".equalsIgnoreCase(generator)) return "integer"; 771 if("identity".equalsIgnoreCase(generator)) return "integer"; 772 if("native".equalsIgnoreCase(generator)) return "integer"; 773 if("seqhilo".equalsIgnoreCase(generator)) return "string"; 774 if("uuid".equalsIgnoreCase(generator)) return "string"; 775 if("guid".equalsIgnoreCase(generator)) return "string"; 776 if("select".equalsIgnoreCase(generator)) return "string"; 777 return defaultValue; 778 } 779 780 private static String getType(ColumnInfo info, Component cfc,Property prop,Struct meta,String defaultValue, SessionFactoryData data) throws PageException { 781 // ormType 782 String type = toString(cfc,prop,meta,"ormType",data); 783 //type=HibernateCaster.toHibernateType(info,type,null); 784 785 // dataType 786 if(Util.isEmpty(type,true)){ 787 type=toString(cfc,prop,meta,"dataType",data); 788 //type=HibernateCaster.toHibernateType(info,type,null); 789 } 790 791 // type 792 if(Util.isEmpty(type,true)){ 793 type=prop.getType(); 794 //type=HibernateCaster.toHibernateType(info,type,null); 795 } 796 797 // type from db info 798 if(Util.isEmpty(type,true)){ 799 if(info!=null){ 800 type=info.getTypeName(); 801 //type=HibernateCaster.toHibernateType(info,type,defaultValue); 802 } 803 else return defaultValue; 804 } 805 return HibernateCaster.toHibernateType(info,type,defaultValue); 806 } 807 808 809 810 811 812 813 814 815 816 private static ColumnInfo getColumnInfo(Struct columnsInfo,String tableName,String columnName,ColumnInfo defaultValue) { 817 if(columnsInfo!=null) { 818 ColumnInfo info = (ColumnInfo) columnsInfo.get(CommonUtil.createKey(columnName),null); 819 if(info==null) return defaultValue; 820 return info; 821 } 822 return defaultValue; 823 } 824 825 private static String createXMLMappingGenerator(Element id,Component cfc,Property prop,StringBuilder foreignCFC, SessionFactoryData data) throws PageException { 826 Struct meta = prop.getDynamicAttributes(); 827 828 // generator 829 String className=toString(cfc,prop,meta,"generator",data); 830 if(Util.isEmpty(className,true)) return null; 831 832 833 Document doc = CommonUtil.getDocument(id); 834 Element generator = doc.createElement("generator"); 835 id.appendChild(generator); 836 837 generator.setAttribute("class", className); 838 839 //print.e("generator:"+className); 840 841 // params 842 Object obj=meta.get(PARAMS,null); 843 //if(obj!=null){ 844 Struct sct=null; 845 if(obj==null) obj=CommonUtil.createStruct(); 846 else if(obj instanceof String) obj=ORMUtil.convertToSimpleMap((String)obj); 847 848 if(CommonUtil.isStruct(obj)) sct=CommonUtil.toStruct(obj); 849 else throw ExceptionUtil.createException(data,cfc,"invalid value for attribute [params] of tag [property]",null); 850 className=className.trim().toLowerCase(); 851 852 // special classes 853 if("foreign".equals(className)){ 854 if(!sct.containsKey(PROPERTY)) sct.setEL(PROPERTY, toString(cfc,prop,meta, PROPERTY,true,data)); 855 856 if(sct.containsKey(PROPERTY)){ 857 String p = CommonUtil.toString(sct.get(PROPERTY),null); 858 if(!Util.isEmpty(p))foreignCFC.append(p); 859 } 860 861 862 } 863 else if("select".equals(className)){ 864 //print.e("select:"+toString(meta, "selectKey",true)); 865 if(!sct.containsKey(KEY)) sct.setEL(KEY, toString(cfc,prop,meta, "selectKey",true,data)); 866 } 867 else if("sequence".equals(className)){ 868 if(!sct.containsKey(SEQUENCE)) sct.setEL(SEQUENCE, toString(cfc,prop,meta, "sequence",true,data)); 869 } 870 871 //Key[] keys = sct.keys(); 872 Iterator<Entry<Key, Object>> it = sct.entryIterator(); 873 Entry<Key, Object> e; 874 Element param; 875 while(it.hasNext()){ 876 e = it.next(); 877 param = doc.createElement("param"); 878 generator.appendChild(param); 879 880 param.setAttribute( "name", e.getKey().getLowerString()); 881 param.appendChild(doc.createTextNode(CommonUtil.toString(e.getValue()))); 882 883 } 884 //} 885 return className; 886 } 887 888 889 890 891 892 893 894 private static void createXMLMappingProperty(Element clazz, PageContext pc,Component cfc,Property prop,Struct columnsInfo,String tableName,SessionFactoryData data) throws PageException { 895 Struct meta = prop.getDynamicAttributes(); 896 897 898 899 // get table name 900 String columnName=toString(cfc,prop,meta,"column",data); 901 if(Util.isEmpty(columnName,true)) columnName=prop.getName(); 902 903 ColumnInfo info=getColumnInfo(columnsInfo,tableName,columnName,null); 904 905 Document doc = CommonUtil.getDocument(clazz); 906 final Element property = doc.createElement("property"); 907 clazz.appendChild(property); 908 909 //name 910 property.setAttribute("name",prop.getName()); 911 912 // type 913 String str = getType(info, cfc,prop, meta, "string",data); 914 property.setAttribute("type",str); 915 916 917 918 // formula or column 919 str=toString(cfc,prop,meta,"formula",data); 920 Boolean b; 921 if(!Util.isEmpty(str,true)) { 922 property.setAttribute("formula","("+str+")"); 923 } 924 else { 925 //property.setAttribute("column",columnName); 926 927 Element column = doc.createElement("column"); 928 property.appendChild(column); 929 column.setAttribute("name", escape(HibernateUtil.convertColumnName(data,columnName))); 930 931 // check 932 str=toString(cfc,prop,meta,"check",data); 933 if(!Util.isEmpty(str,true)) column.setAttribute("check",str); 934 935 // default 936 str=toString(cfc,prop,meta,"dbDefault",data); 937 if(!Util.isEmpty(str,true)) column.setAttribute("default",str); 938 939 // index 940 str=toString(cfc,prop,meta,"index",data); 941 if(!Util.isEmpty(str,true)) column.setAttribute("index",str); 942 943 // length 944 Integer i = toInteger(cfc,meta,"length",data); 945 if(i!=null && i>0) column.setAttribute("length",CommonUtil.toString(i.intValue())); 946 947 // not-null 948 b=toBoolean(cfc,meta,"notnull",data); 949 if(b!=null && b.booleanValue())column.setAttribute("not-null","true"); 950 951 // precision 952 i=toInteger(cfc,meta,"precision",data); 953 if(i!=null && i>-1) column.setAttribute("precision",CommonUtil.toString(i.intValue())); 954 955 // scale 956 i=toInteger(cfc,meta,"scale",data); 957 if(i!=null && i>-1) column.setAttribute("scale",CommonUtil.toString(i.intValue())); 958 959 // sql-type 960 str=toString(cfc,prop,meta,"sqltype",data); 961 if(!Util.isEmpty(str,true)) column.setAttribute("sql-type",str); 962 963 // unique 964 b=toBoolean(cfc,meta,"unique",data); 965 if(b!=null && b.booleanValue())column.setAttribute("unique","true"); 966 967 // unique-key 968 str=toString(cfc,prop,meta,"uniqueKey",data); 969 if(Util.isEmpty(str))str=CommonUtil.toString(meta.get(UNIQUE_KEY_NAME,null),null); 970 if(!Util.isEmpty(str,true)) column.setAttribute("unique-key",str); 971 972 973 } 974 975 // generated 976 str=toString(cfc,prop,meta,"generated",data); 977 if(!Util.isEmpty(str,true)){ 978 str=str.trim().toLowerCase(); 979 980 if("always".equals(str) || "insert".equals(str) || "never".equals(str)) 981 property.setAttribute("generated",str); 982 else 983 throw invalidValue(cfc,prop,"generated",str,"always,insert,never",data); 984 //throw new ORMException("invalid value ["+str+"] for attribute [generated] of column ["+columnName+"], valid values are [always,insert,never]"); 985 } 986 987 988 // update 989 b=toBoolean(cfc,meta,"update",data); 990 if(b!=null && !b.booleanValue())property.setAttribute("update","false"); 991 992 // insert 993 b=toBoolean(cfc,meta,"insert",data); 994 if(b!=null && !b.booleanValue())property.setAttribute("insert","false"); 995 996 // lazy (dtd defintion:<!ATTLIST property lazy (true|false) "false">) 997 b=toBoolean(cfc,meta,"lazy",data); 998 if(b!=null && b.booleanValue())property.setAttribute("lazy","true"); 999 1000 // optimistic-lock 1001 b=toBoolean(cfc,meta,"optimisticlock",data); 1002 if(b!=null && !b.booleanValue())property.setAttribute("optimistic-lock","false"); 1003 1004 } 1005 1006 1007 /* 1008 MUST dies kommt aber nicht hier sondern in verarbeitung in component 1009 <cfproperty 1010 persistent="true|false" 1011 > 1012 * */ 1013 private static void createXMLMappingOneToOne(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException { 1014 Struct meta = prop.getDynamicAttributes(); 1015 1016 Boolean b; 1017 1018 Document doc = CommonUtil.getDocument(clazz); 1019 Element x2o; 1020 1021 // column 1022 String fkcolumn=toString(cfc,prop,meta,"fkcolumn",data); 1023 String linkTable=toString(cfc,prop,meta,"linkTable",data); 1024 1025 1026 if(!Util.isEmpty(linkTable,true) || !Util.isEmpty(fkcolumn,true)) { 1027 clazz=getJoin(clazz); 1028 1029 x2o= doc.createElement("many-to-one"); 1030 //x2o.setAttribute("column", fkcolumn); 1031 x2o.setAttribute("unique", "true"); 1032 1033 if(!Util.isEmpty(linkTable,true)){ 1034 setColumn(doc, x2o, linkTable,data); 1035 } 1036 else { 1037 setColumn(doc, x2o, fkcolumn,data); 1038 } 1039 1040 1041 1042 1043 // update 1044 b=toBoolean(cfc,meta,"update",data); 1045 if(b!=null)x2o.setAttribute("update",CommonUtil.toString(b.booleanValue())); 1046 1047 // insert 1048 b=toBoolean(cfc,meta,"insert",data); 1049 if(b!=null)x2o.setAttribute("insert",CommonUtil.toString(b.booleanValue())); 1050 1051 // not-null 1052 b=toBoolean(cfc,meta,"notNull",data); 1053 if(b!=null)x2o.setAttribute("not-null",CommonUtil.toString(b.booleanValue())); 1054 1055 1056 // optimistic-lock 1057 b=toBoolean(cfc,meta,"optimisticLock",data); 1058 if(b!=null)x2o.setAttribute("optimistic-lock",CommonUtil.toString(b.booleanValue())); 1059 1060 // not-found 1061 b=toBoolean(cfc,meta, "missingRowIgnored",data); 1062 if(b!=null && b.booleanValue()) x2o.setAttribute("not-found", "ignore"); 1063 1064 /* / index 1065 str=toString(meta,"index"); 1066 if(!Util.isEmpty(str,true)) x2o.setAttribute("index", str); 1067 */ 1068 1069 1070 } 1071 else { 1072 x2o= doc.createElement("one-to-one"); 1073 } 1074 clazz.appendChild(x2o); 1075 1076 // access 1077 String str=toString(cfc,prop,meta,"access",data); 1078 if(!Util.isEmpty(str,true)) x2o.setAttribute("access", str); 1079 1080 // constrained 1081 b=toBoolean(cfc,meta, "constrained",data); 1082 if(b!=null && b.booleanValue()) x2o.setAttribute("constrained", "true"); 1083 1084 // formula 1085 str=toString(cfc,prop,meta,"formula",data); 1086 if(!Util.isEmpty(str,true)) x2o.setAttribute("formula", str); 1087 1088 // embed-xml 1089 str=toString(cfc,prop,meta,"embedXml",data); 1090 if(!Util.isEmpty(str,true)) x2o.setAttribute("embed-xml", str); 1091 1092 // property-ref 1093 str=toString(cfc,prop,meta,"mappedBy",data); 1094 if(!Util.isEmpty(str,true)) x2o.setAttribute("property-ref", str); 1095 1096 // foreign-key 1097 str=toString(cfc,prop,meta,"foreignKeyName",data); 1098 if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data); 1099 if(!Util.isEmpty(str,true)) x2o.setAttribute("foreign-key", str); 1100 1101 setForeignEntityName(cfc,prop,meta,x2o,true,data); 1102 1103 createXMLMappingXToX(x2o, pc,cfc,prop,meta,data); 1104 } 1105 1106 1107 1108 1109 1110 1111 private static Component loadForeignCFC(PageContext pc,Component cfc,Property prop, Struct meta, SessionFactoryData data) throws PageException { 1112 // entity 1113 String str=toString(cfc,prop,meta,"entityName",data); 1114 Component fcfc=null; 1115 1116 if(!Util.isEmpty(str,true)) { 1117 fcfc = data.getEntityByEntityName(str, false); 1118 if(fcfc!=null) return fcfc; 1119 } 1120 1121 str = toString(cfc,prop,meta,"cfc",false,data); 1122 if(!Util.isEmpty(str,true)){ 1123 return data.getEntityByCFCName(str, false); 1124 } 1125 return null; 1126 } 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 private static void createXMLMappingCollection(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException { 1137 Struct meta = prop.getDynamicAttributes(); 1138 Document doc = CommonUtil.getDocument(clazz); 1139 Element el=null; 1140 1141 // collection type 1142 String str=prop.getType(); 1143 if(Util.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array"; 1144 else str=str.trim().toLowerCase(); 1145 1146 1147 1148 // bag 1149 if("array".equals(str) || "bag".equals(str)){ 1150 el = doc.createElement("bag"); 1151 } 1152 // map 1153 else if("struct".equals(str) || "map".equals(str)){ 1154 el = doc.createElement("map"); 1155 1156 1157 // map-key 1158 str=toString(cfc,prop,meta,"structKeyColumn",true,data); 1159 if(!Util.isEmpty(str,true)) { 1160 Element mapKey=doc.createElement("map-key"); 1161 el.appendChild(mapKey); 1162 mapKey.setAttribute("column", str); 1163 1164 // type 1165 str=toString(cfc,prop,meta,"structKeyType",data); 1166 if(!Util.isEmpty(str,true))mapKey.setAttribute("type", str); 1167 else mapKey.setAttribute("type", "string"); 1168 } 1169 } 1170 else throw invalidValue(cfc,prop,"collectiontype",str,"array,struct",data); 1171 //throw new ORMException("invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]"); 1172 1173 setBeforeJoin(clazz,el); 1174 1175 // name 1176 el.setAttribute("name", prop.getName()); 1177 1178 // table 1179 str=toString(cfc,prop,meta, "table",true,data); 1180 el.setAttribute("table",escape(HibernateUtil.convertTableName(data,str))); 1181 1182 // catalog 1183 str=toString(cfc,prop,meta, "catalog",data); 1184 if(!Util.isEmpty(str,true))el.setAttribute("catalog",str); 1185 1186 // schema 1187 str=toString(cfc,prop,meta, "schema",data); 1188 if(!Util.isEmpty(str,true))el.setAttribute("schema",str); 1189 1190 // mutable 1191 Boolean b=toBoolean(cfc,meta, "readonly",data); 1192 if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false"); 1193 1194 // order-by 1195 str=toString(cfc,prop,meta, "orderby",data); 1196 if(!Util.isEmpty(str,true))el.setAttribute("order-by",str); 1197 1198 // element-column 1199 str=toString(cfc,prop,meta,"elementcolumn",data); 1200 if(!Util.isEmpty(str,true)){ 1201 Element element = doc.createElement("element"); 1202 el.appendChild(element); 1203 1204 // column 1205 element.setAttribute("column", formatColumn(str,data)); 1206 1207 // type 1208 str=toString(cfc,prop,meta,"elementtype",data); 1209 if(!Util.isEmpty(str,true)) element.setAttribute("type", str); 1210 } 1211 1212 // batch-size 1213 Integer i=toInteger(cfc,meta, "batchsize",data); 1214 if(i!=null && i.intValue()>1) el.setAttribute("batch-size", CommonUtil.toString(i.intValue())); 1215 1216 // column 1217 str=toString(cfc,prop,meta,"fkcolumn",data); 1218 if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"column",data); 1219 if(!Util.isEmpty(str,true)){ 1220 Element key = doc.createElement("key"); 1221 CommonUtil.setFirst(el,key); 1222 //el.appendChild(key); 1223 1224 // column 1225 key.setAttribute("column", formatColumn(str,data)); 1226 1227 // property-ref 1228 str=toString(cfc,prop,meta,"mappedBy",data); 1229 if(!Util.isEmpty(str,true)) key.setAttribute("property-ref", str); 1230 } 1231 1232 // cache 1233 setCacheStrategy(cfc,prop,doc, meta, el,data); 1234 1235 // optimistic-lock 1236 b=toBoolean(cfc,meta, "optimisticlock",data); 1237 if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false"); 1238 1239 1240 } 1241 1242 1243 private static void setBeforeJoin(Element clazz, Element el) { 1244 Element join; 1245 if(clazz.getNodeName().equals("join")) { 1246 join=clazz; 1247 clazz = getClazz(clazz); 1248 } 1249 else { 1250 join = getJoin(clazz); 1251 } 1252 1253 if(join==clazz) clazz.appendChild(el); 1254 else clazz.insertBefore(el, join); 1255 1256 1257 } 1258 1259 private static Element getClazz(Element join) { 1260 if(join.getNodeName().equals("join")){ 1261 return (Element) join.getParentNode(); 1262 } 1263 return join; 1264 } 1265 1266 private static Element getJoin(Element clazz) { 1267 if(clazz.getNodeName().equals("subclass")){ 1268 NodeList joins = clazz.getElementsByTagName("join"); 1269 if(joins!=null && joins.getLength()>0) 1270 return (Element)joins.item(0); 1271 } 1272 return clazz; 1273 } 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 private static void createXMLMappingManyToMany(Component cfc,PropertyCollection propColl,Element clazz, PageContext pc,Property prop,DatasourceConnection dc, SessionFactoryData data) throws PageException { 1287 Element el = createXMLMappingXToMany(propColl,clazz, pc, cfc,prop,data); 1288 Struct meta = prop.getDynamicAttributes(); 1289 Document doc = CommonUtil.getDocument(clazz); 1290 Element m2m = doc.createElement("many-to-many"); 1291 el.appendChild(m2m); 1292 1293 // link 1294 setLink(cfc,prop,el,meta,true,data); 1295 1296 setForeignEntityName(cfc,prop, meta, m2m,true,data); 1297 1298 // order-by 1299 String str = toString(cfc,prop,meta,"orderby",data); 1300 if(!Util.isEmpty(str,true))m2m.setAttribute("order-by", str); 1301 1302 // column 1303 str=toString(cfc,prop,meta,"inversejoincolumn",data); 1304 1305 // build fkcolumn name 1306 if(Util.isEmpty(str,true)) { 1307 Component other = loadForeignCFC(pc, cfc, prop, meta,data); 1308 if(other!=null){ 1309 boolean isClass=Util.isEmpty(other.getExtends()); 1310 // MZ: Recursive search for persistent mappedSuperclass properties 1311 Property[] _props=getProperties(pc,other,dc,meta,isClass, true,data); 1312 PropertyCollection _propColl = splitJoins(cfc,new HashMap<String, PropertyCollection>(), _props,data); 1313 _props=_propColl.getProperties(); 1314 1315 Struct m; 1316 Property _prop=null; 1317 for(int i=0;i<_props.length;i++){ 1318 m = _props[i].getDynamicAttributes(); 1319 // fieldtype 1320 String fieldtype = CommonUtil.toString(m.get(FIELDTYPE,null),null); 1321 if("many-to-many".equalsIgnoreCase(fieldtype)) { 1322 // linktable 1323 String currLinkTable=CommonUtil.toString(meta.get(LINK_TABLE,null),null); 1324 String othLinkTable=CommonUtil.toString(m.get(LINK_TABLE,null),null); 1325 if(currLinkTable.equals(othLinkTable)) { 1326 // cfc name 1327 String cfcName=CommonUtil.toString(m.get(CFC,null),null); 1328 if(cfc.equalTo(cfcName)){ 1329 _prop=_props[i]; 1330 } 1331 } 1332 } 1333 } 1334 str=createM2MFKColumnName( other, _prop, _propColl,data); 1335 } 1336 } 1337 setColumn(doc, m2m, str,data); 1338 1339 // not-found 1340 Boolean b=toBoolean(cfc,meta, "missingrowignored",data); 1341 if(b!=null && b.booleanValue()) m2m.setAttribute("not-found", "ignore"); 1342 1343 // property-ref 1344 str=toString(cfc,prop,meta,"mappedby",data); 1345 if(!Util.isEmpty(str,true)) m2m.setAttribute("property-ref", str); 1346 1347 // foreign-key 1348 str=toString(cfc,prop,meta,"foreignKeyName",data); 1349 if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data); 1350 if(!Util.isEmpty(str,true)) m2m.setAttribute("foreign-key", str); 1351 } 1352 1353 private static boolean setLink(Component cfc,Property prop,Element el, Struct meta, boolean linkTableRequired,SessionFactoryData data) throws PageException { 1354 String str=toString(cfc,prop,meta, "linktable",linkTableRequired,data); 1355 1356 1357 if(!Util.isEmpty(str,true)){ 1358 1359 el.setAttribute("table", escape(HibernateUtil.convertTableName(data,str))); 1360 1361 // schema 1362 str=toString(cfc,prop,meta, "linkschema",data); 1363 if(Util.isEmpty(str,true)) str=data.getORMConfiguration().getSchema(); 1364 if(!Util.isEmpty(str,true)) el.setAttribute("schema", str); 1365 1366 // catalog 1367 str=toString(cfc,prop,meta, "linkcatalog",data); 1368 if(Util.isEmpty(str,true)) str=data.getORMConfiguration().getCatalog(); 1369 if(!Util.isEmpty(str,true)) el.setAttribute("catalog", str); 1370 return true; 1371 } 1372 return false; 1373 } 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 private static void createXMLMappingOneToMany(Component cfc,PropertyCollection propColl,Element clazz, PageContext pc,Property prop, SessionFactoryData data) throws PageException { 1384 Element el = createXMLMappingXToMany(propColl,clazz, pc, cfc,prop,data); 1385 Struct meta = prop.getDynamicAttributes(); 1386 Document doc = CommonUtil.getDocument(clazz); 1387 Element x2m; 1388 1389 1390 // order-by 1391 String str = toString(cfc,prop,meta,"orderby",data); 1392 if(!Util.isEmpty(str,true))el.setAttribute("order-by", str); 1393 1394 // link 1395 if(setLink(cfc,prop,el,meta,false,data)){ 1396 x2m = doc.createElement("many-to-many"); 1397 x2m.setAttribute("unique","true"); 1398 1399 str=toString(cfc,prop,meta,"inversejoincolumn",data); 1400 setColumn(doc, x2m, str,data); 1401 } 1402 else { 1403 x2m = doc.createElement("one-to-many"); 1404 } 1405 el.appendChild(x2m); 1406 1407 1408 // entity-name 1409 1410 setForeignEntityName(cfc,prop,meta,x2m,true,data); 1411 1412 } 1413 1414 1415 1416 1417 1418 1419 1420 1421 private static Element createXMLMappingXToMany(PropertyCollection propColl,Element clazz, PageContext pc,Component cfc,Property prop, SessionFactoryData data) throws PageException { 1422 final Struct meta = prop.getDynamicAttributes(); 1423 Document doc = CommonUtil.getDocument(clazz); 1424 Element el=null; 1425 1426 1427 1428 // collection type 1429 String str=prop.getType(); 1430 if(Util.isEmpty(str,true) || "any".equalsIgnoreCase(str) || "object".equalsIgnoreCase(str))str="array"; 1431 else str=str.trim().toLowerCase(); 1432 1433 Element mapKey=null; 1434 // bag 1435 if("array".equals(str) || "bag".equals(str)){ 1436 el = doc.createElement("bag"); 1437 1438 } 1439 // map 1440 else if("struct".equals(str) || "map".equals(str)){ 1441 el = doc.createElement("map"); 1442 1443 // map-key 1444 mapKey = doc.createElement("map-key"); 1445 //el.appendChild(mapKey); 1446 1447 // column 1448 str=toString(cfc,prop,meta,"structKeyColumn",true,data); 1449 mapKey.setAttribute("column", formatColumn(str,data)); 1450 1451 // type 1452 str=toString(cfc,prop,meta,"structKeyType",data); 1453 if(!Util.isEmpty(str,true))mapKey.setAttribute("type", str); 1454 else mapKey.setAttribute("type", "string");// MUST get type dynamicly 1455 } 1456 else throw invalidValue(cfc,prop,"collectiontype",str,"array,struct",data); 1457 //throw new ORMException("invalid value ["+str+"] for attribute [collectiontype], valid values are [array,struct]"); 1458 1459 setBeforeJoin(clazz,el); 1460 1461 1462 1463 // batch-size 1464 Integer i=toInteger(cfc,meta, "batchsize",data); 1465 if(i!=null){ 1466 if(i.intValue()>1) el.setAttribute("batch-size", CommonUtil.toString(i.intValue())); 1467 } 1468 1469 // cacheUse 1470 setCacheStrategy(cfc,prop,doc, meta, el,data); 1471 1472 // column 1473 str=createFKColumnName(cfc,prop,propColl,data); 1474 1475 if(!Util.isEmpty(str,true)){ 1476 Element key = doc.createElement("key"); 1477 el.appendChild(key); 1478 1479 // column 1480 setColumn(doc,key,str,data); 1481 1482 // property-ref 1483 str=toString(cfc,prop,meta,"mappedBy",data); 1484 if(!Util.isEmpty(str,true)) key.setAttribute("property-ref", str); 1485 } 1486 1487 // inverse 1488 Boolean b = toBoolean(cfc,meta, "inverse",data); 1489 if(b!=null && b.booleanValue()) el.setAttribute("inverse", "true"); 1490 1491 1492 1493 // mutable 1494 b = toBoolean(cfc,meta, "readonly",data); 1495 if(b!=null && b.booleanValue()) el.setAttribute("mutable", "false"); 1496 1497 // optimistic-lock 1498 b=toBoolean(cfc,meta, "optimisticlock",data); 1499 if(b!=null && !b.booleanValue()) el.setAttribute("optimistic-lock", "false"); 1500 1501 // where 1502 str=toString(cfc,prop,meta,"where",data); 1503 if(!Util.isEmpty(str,true)) el.setAttribute("where", str); 1504 1505 // add map key 1506 if(mapKey!=null)el.appendChild(mapKey); 1507 1508 1509 createXMLMappingXToX(el, pc,cfc,prop,meta,data); 1510 1511 return el; 1512 } 1513 1514 1515 1516 private static String createFKColumnName(Component cfc, Property prop, PropertyCollection propColl, SessionFactoryData data) throws PageException { 1517 1518 1519 // fk column from local defintion 1520 String str=prop==null?null:toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",data); 1521 if(!Util.isEmpty(str)) 1522 return str; 1523 1524 // no local defintion, get from Foreign enity 1525 Struct meta = prop.getDynamicAttributes(); 1526 String type=toString(cfc,prop,meta,"fieldtype",false,data); 1527 String otherType; 1528 if("many-to-one".equalsIgnoreCase(type)) otherType="one-to-many"; 1529 else if("one-to-many".equalsIgnoreCase(type)) otherType="many-to-one"; 1530 else return createM2MFKColumnName( cfc, prop, propColl,data); 1531 1532 String feName = toString(cfc,prop,meta,"cfc",true,data); 1533 Component feCFC=data.getEntityByCFCName(feName, false); 1534 Property[] feProps = feCFC.getProperties(true); 1535 1536 Property p; 1537 Component _cfc; 1538 for(int i=0;i<feProps.length;i++){ 1539 p=feProps[i]; 1540 1541 // compare fieldType 1542 str=toString(feCFC,p,p.getDynamicAttributes(),"fieldtype",false,data); 1543 if(!otherType.equalsIgnoreCase(str)) continue; 1544 1545 // compare cfc 1546 str=toString(feCFC,p,p.getDynamicAttributes(),"cfc",false,data); 1547 if(Util.isEmpty(str)) continue; 1548 _cfc=data.getEntityByCFCName(str, false); 1549 if(_cfc==null || !_cfc.equals(cfc))continue; 1550 1551 // get fkcolumn 1552 str=toString(_cfc,p,p.getDynamicAttributes(),"fkcolumn",data); 1553 if(!Util.isEmpty(str)) return str; 1554 1555 1556 } 1557 throw ExceptionUtil.createException(data,null,"cannot terminate foreign key column name for component "+cfc.getName(),null); 1558 } 1559 1560 1561 private static String createM2MFKColumnName(Component cfc, Property prop, PropertyCollection propColl,SessionFactoryData data) throws PageException { 1562 1563 String str=prop==null?null:toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",data); 1564 if(Util.isEmpty(str)){ 1565 Property[] ids = getIds(cfc,propColl,data); 1566 if(ids.length==1) { 1567 str=toString(cfc,ids[0],ids[0].getDynamicAttributes(),"column",data); 1568 if(Util.isEmpty(str,true)) str=ids[0].getName(); 1569 } 1570 else if(prop!=null)str=toString(cfc,prop,prop.getDynamicAttributes(),"fkcolumn",true,data); 1571 else 1572 throw ExceptionUtil.createException(data,null,"cannot terminate foreign key column name for component "+cfc.getName(),null); 1573 1574 str=HibernateCaster.getEntityName(cfc)+"_"+str; 1575 } 1576 return str; 1577 } 1578 1579 private static void setForeignEntityName(Component cfc,Property prop, Struct meta, Element el, boolean cfcRequired, SessionFactoryData data) throws PageException { 1580 // entity 1581 String str=cfcRequired?null:toString(cfc,prop,meta,"entityName",data); 1582 if(!Util.isEmpty(str,true)) { 1583 el.setAttribute("entity-name", str); 1584 } 1585 else { 1586 // cfc 1587 //createFKColumnName( cfc, prop, propColl); 1588 1589 str = toString(cfc,prop,meta,"cfc",cfcRequired,data); 1590 if(!Util.isEmpty(str,true)){ 1591 Component _cfc=data.getEntityByCFCName(str, false); 1592 str=HibernateCaster.getEntityName(_cfc); 1593 el.setAttribute("entity-name", str); 1594 } 1595 } 1596 } 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 private static void setCacheStrategy(Component cfc,Property prop,Document doc,Struct meta, Element el, SessionFactoryData data) throws PageException { 1607 String strategy = toString(cfc,prop,meta,"cacheuse",data); 1608 1609 if(!Util.isEmpty(strategy,true)){ 1610 strategy=strategy.trim().toLowerCase(); 1611 if("read-only".equals(strategy) || "nonstrict-read-write".equals(strategy) || "read-write".equals(strategy) || "transactional".equals(strategy)){ 1612 Element cache = doc.createElement("cache"); 1613 CommonUtil.setFirst(el, cache); 1614 el.appendChild(cache); 1615 cache.setAttribute("usage", strategy); 1616 String name = toString(cfc,prop,meta,"cacheName",data); 1617 if(!Util.isEmpty(name,true)){ 1618 cache.setAttribute("region", name); 1619 } 1620 } 1621 else 1622 throw ExceptionUtil.createException(data,cfc,"invalid value ["+strategy+"] for attribute [cacheuse], valid values are [read-only,nonstrict-read-write,read-write,transactional]",null); 1623 } 1624 1625 } 1626 1627 1628 1629 1630 1631 1632 1633 private static void setColumn(Document doc, Element el, String columnValue,SessionFactoryData data) throws PageException { 1634 if(Util.isEmpty(columnValue,true)) return; 1635 1636 String[] arr = CommonUtil.toStringArray(columnValue, ','); 1637 if(arr.length==1){ 1638 el.setAttribute("column", formatColumn(arr[0],data)); 1639 } 1640 else { 1641 Element column; 1642 for(int i=0;i<arr.length;i++){ 1643 column=doc.createElement("column"); 1644 el.appendChild(column); 1645 column.setAttribute("name", formatColumn(arr[i],data)); 1646 } 1647 } 1648 } 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 private static void createXMLMappingManyToOne(Element clazz, PageContext pc,Component cfc,Property prop, PropertyCollection propColl, SessionFactoryData data) throws PageException { 1659 Struct meta = prop.getDynamicAttributes(); 1660 Boolean b; 1661 1662 Document doc = CommonUtil.getDocument(clazz); 1663 clazz=getJoin(clazz); 1664 1665 Element m2o = doc.createElement("many-to-one"); 1666 clazz.appendChild(m2o); 1667 1668 // columns 1669 String linktable = toString(cfc,prop,meta,"linktable",data); 1670 String _columns; 1671 if(!Util.isEmpty(linktable,true)) _columns=toString(cfc,prop,meta,"inversejoincolumn",data); 1672 else _columns=createFKColumnName(cfc, prop, propColl,data);//toString(cfc,prop,meta,"fkcolumn"); 1673 setColumn(doc, m2o, _columns,data); 1674 1675 // cfc 1676 setForeignEntityName(cfc,prop,meta,m2o,true,data); 1677 1678 // column 1679 //String str=toString(prop,meta,"column",true); 1680 //m2o.setAttribute("column", str); 1681 1682 // insert 1683 b=toBoolean(cfc,meta, "insert",data); 1684 if(b!=null && !b.booleanValue()) m2o.setAttribute("insert", "false"); 1685 1686 // update 1687 b=toBoolean(cfc,meta, "update",data); 1688 if(b!=null && !b.booleanValue()) m2o.setAttribute("update", "false"); 1689 1690 // property-ref 1691 String str=toString(cfc,prop,meta,"mappedBy",data); 1692 if(!Util.isEmpty(str,true)) m2o.setAttribute("property-ref", str); 1693 1694 // update 1695 b=toBoolean(cfc,meta, "unique",data); 1696 if(b!=null && b.booleanValue()) m2o.setAttribute("unique", "true"); 1697 1698 // not-null 1699 b=toBoolean(cfc,meta, "notnull",data); 1700 if(b!=null && b.booleanValue()) m2o.setAttribute("not-null", "true"); 1701 1702 // optimistic-lock 1703 b=toBoolean(cfc,meta, "optimisticLock",data); 1704 if(b!=null && !b.booleanValue()) m2o.setAttribute("optimistic-lock", "false"); 1705 1706 // not-found 1707 b=toBoolean(cfc,meta, "missingRowIgnored",data); 1708 if(b!=null && b.booleanValue()) m2o.setAttribute("not-found", "ignore"); 1709 1710 // index 1711 str=toString(cfc,prop,meta,"index",data); 1712 if(!Util.isEmpty(str,true)) m2o.setAttribute("index", str); 1713 1714 // unique-key 1715 str=toString(cfc,prop,meta,"uniqueKeyName",data); 1716 if(Util.isEmpty(str,true))str=toString(cfc,prop,meta,"uniqueKey",data); 1717 if(!Util.isEmpty(str,true)) m2o.setAttribute("unique-key", str); 1718 1719 // foreign-key 1720 str=toString(cfc,prop,meta,"foreignKeyName",data); 1721 if(Util.isEmpty(str,true)) str=toString(cfc,prop,meta,"foreignKey",data); 1722 if(!Util.isEmpty(str,true)) m2o.setAttribute("foreign-key", str); 1723 1724 // access 1725 str=toString(cfc,prop,meta,"access",data); 1726 if(!Util.isEmpty(str,true)) m2o.setAttribute("access", str); 1727 1728 createXMLMappingXToX(m2o, pc,cfc,prop,meta,data); 1729 1730 } 1731 1732 1733 1734 1735 1736 1737 1738 1739 private static String formatColumn(String name,SessionFactoryData data) throws PageException { 1740 name=name.trim(); 1741 return escape(HibernateUtil.convertColumnName(data,name)); 1742 } 1743 1744 /* 1745 1746 1747 <cfproperty 1748cfc="Referenced_CFC_Name" 1749linktable="Link table name" 1750linkcatalog="Catalog for the link table" 1751linkschema="Schema for the link table" 1752fkcolumn="Foreign Key column name" 1753inversejoincolumn="Column name or comma-separated list of primary key columns" 1754 1755 1756> 1757 1758 */ 1759 private static void createXMLMappingXToX(Element x2x, PageContext pc, Component cfc,Property prop, Struct meta, SessionFactoryData data) throws PageException { 1760 x2x.setAttribute("name",prop.getName()); 1761 1762 // cascade 1763 String str=toString(cfc,prop,meta,"cascade",data); 1764 if(!Util.isEmpty(str,true)) x2x.setAttribute("cascade", str); 1765 1766 // fetch 1767 str=toString(cfc,prop,meta,"fetch",data); 1768 if(!Util.isEmpty(str,true)) { 1769 str=str.trim().toLowerCase(); 1770 if("join".equals(str) || "select".equals(str)) 1771 x2x.setAttribute("fetch", str); 1772 else 1773 throw invalidValue(cfc,prop,"fetch",str,"join,select",data); 1774 //throw new ORMException("invalid value ["+str+"] for attribute [fetch], valid values are [join,select]"); 1775 } 1776 1777 // lazy 1778 setLazy(cfc,prop,meta,x2x,data); 1779 1780 } 1781 1782 1783 1784 1785 1786 private static void setLazy(Component cfc,Property prop, Struct meta, Element x2x, SessionFactoryData data) throws PageException { 1787 String str = toString(cfc,prop,meta, "lazy",data); 1788 if(!Util.isEmpty(str,true)){ 1789 str=str.trim(); 1790 String name=x2x.getNodeName(); 1791 Boolean b = CommonUtil.toBoolean(str,null); 1792 1793 // <!ATTLIST many-to-one lazy (false|proxy|no-proxy) #IMPLIED> 1794 // <!ATTLIST one-to-one lazy (false|proxy|no-proxy) #IMPLIED> 1795 if("many-to-one".equals(name) || "one-to-one".equals(name)) { 1796 if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false"); 1797 else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy"); 1798 else if("no-proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "no-proxy"); 1799 else throw invalidValue(cfc,prop,"lazy",str,"true,false,proxy,no-proxy",data); 1800 } 1801 1802 1803 // <!ATTLIST many-to-many lazy (false|proxy) #IMPLIED> 1804 // <!ATTLIST key-many-to-one lazy (false|proxy) #IMPLIED> 1805 else if("many-to-many".equals(name) || "key-many-to-one".equals(name)) { 1806 if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"proxy":"false"); 1807 else if("proxy".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "proxy"); 1808 throw invalidValue(cfc,prop,"lazy",str,"true,false,proxy",data); 1809 1810 } 1811 1812 else { 1813 if(b!=null) x2x.setAttribute("lazy", b.booleanValue()?"true":"false"); 1814 else if("extra".equalsIgnoreCase(str)) x2x.setAttribute("lazy", "extra"); 1815 else throw invalidValue(cfc,prop,"lazy",str,"true,false,extra",data); 1816 } 1817 } 1818 } 1819 1820 private static void createXMLMappingTimestamp(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException { 1821 Struct meta = prop.getDynamicAttributes(); 1822 String str; 1823 Boolean b; 1824 1825 1826 Document doc = CommonUtil.getDocument(clazz); 1827 Element timestamp = doc.createElement("timestamp"); 1828 clazz.appendChild(timestamp); 1829 1830 timestamp.setAttribute("name",prop.getName()); 1831 1832 // access 1833 str=toString(cfc,prop,meta,"access",data); 1834 if(!Util.isEmpty(str,true))timestamp.setAttribute("access", str); 1835 1836 // column 1837 str=toString(cfc,prop,meta,"column",data); 1838 if(Util.isEmpty(str,true)) str=prop.getName(); 1839 timestamp.setAttribute("column",formatColumn(str,data)); 1840 1841 // generated 1842 b=toBoolean(cfc,meta, "generated",data); 1843 if(b!=null) timestamp.setAttribute("generated", b.booleanValue()?"always":"never"); 1844 1845 // source 1846 str=toString(cfc,prop,meta,"source",data); 1847 if(!Util.isEmpty(str,true)) { 1848 str=str.trim().toLowerCase(); 1849 if("db".equals(str) || "vm".equals(str)) 1850 timestamp.setAttribute("source", str); 1851 else 1852 throw invalidValue(cfc,prop,"source",str,"db,vm",data); 1853 } 1854 1855 // unsavedValue 1856 str=toString(cfc,prop,meta,"unsavedValue",data); 1857 if(!Util.isEmpty(str,true)) { 1858 str=str.trim().toLowerCase(); 1859 if("null".equals(str) || "undefined".equals(str)) 1860 timestamp.setAttribute("unsaved-value", str); 1861 else 1862 throw invalidValue(cfc,prop,"unsavedValue",str,"null, undefined",data); 1863 //throw new ORMException("invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, undefined]"); 1864 } 1865 } 1866 1867 1868 private static PageException invalidValue(Component cfc,Property prop, String attrName, String invalid, String valid, SessionFactoryData data) { 1869 String owner = prop.getOwnerName(); 1870 if(Util.isEmpty(owner))return ExceptionUtil.createException(data,cfc,"invalid value ["+invalid+"] for attribute ["+attrName+"] of property ["+prop.getName()+"], valid values are ["+valid+"]",null); 1871 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); 1872 } 1873 1874 1875 1876 1877 1878 1879 private static void createXMLMappingVersion(Element clazz, PageContext pc,Component cfc,Property prop,SessionFactoryData data) throws PageException { 1880 Struct meta = prop.getDynamicAttributes(); 1881 1882 Document doc = CommonUtil.getDocument(clazz); 1883 Element version = doc.createElement("version"); 1884 clazz.appendChild(version); 1885 1886 1887 version.setAttribute("name",prop.getName()); 1888 1889 // column 1890 String str = toString(cfc,prop,meta,"column",data); 1891 if(Util.isEmpty(str,true)) str=prop.getName(); 1892 version.setAttribute("column",formatColumn(str,data)); 1893 1894 // access 1895 str=toString(cfc,prop,meta,"access",data); 1896 if(!Util.isEmpty(str,true))version.setAttribute("access", str); 1897 1898 // generated 1899 Object o=meta.get(GENERATED,null); 1900 if(o!=null){ 1901 Boolean b = CommonUtil.toBoolean(o,null); 1902 str=null; 1903 if(b!=null) { 1904 str=b.booleanValue()?"always":"never"; 1905 } 1906 else { 1907 str=CommonUtil.toString(o,null); 1908 if("always".equalsIgnoreCase(str))str="always"; 1909 else if("never".equalsIgnoreCase(str))str="never"; 1910 else throw invalidValue(cfc,prop,"generated",o.toString(),"true,false,always,never",data); 1911 //throw new ORMException("invalid value ["+o+"] for attribute [generated] of property ["+prop.getName()+"], valid values are [true,false,always,never]"); 1912 } 1913 version.setAttribute( "generated", str); 1914 } 1915 1916 // insert 1917 Boolean b = toBoolean(cfc,meta, "insert",data); 1918 if(b!=null && !b.booleanValue()) version.setAttribute("insert", "false"); 1919 1920 // type 1921 String typeName="dataType"; 1922 str=toString(cfc,prop,meta,typeName,data); 1923 if(Util.isEmpty(str,true)){ 1924 typeName="ormType"; 1925 str=toString(cfc,prop,meta,typeName,data); 1926 } 1927 if(!Util.isEmpty(str,true)) { 1928 str=str.trim().toLowerCase(); 1929 if("int".equals(str) || "integer".equals(str)) 1930 version.setAttribute("type", "integer"); 1931 else if("long".equals(str)) 1932 version.setAttribute("type", "long"); 1933 else if("short".equals(str)) 1934 version.setAttribute("type", "short"); 1935 else 1936 throw invalidValue(cfc,prop,typeName,str,"int,integer,long,short",data); 1937 //throw new ORMException("invalid value ["+str+"] for attribute ["+typeName+"], valid values are [int,integer,long,short]"); 1938 } 1939 else 1940 version.setAttribute("type", "integer"); 1941 1942 // unsavedValue 1943 str=toString(cfc,prop,meta,"unsavedValue",data); 1944 if(!Util.isEmpty(str,true)) { 1945 str=str.trim().toLowerCase(); 1946 if("null".equals(str) || "negative".equals(str) || "undefined".equals(str)) 1947 version.setAttribute("unsaved-value", str); 1948 else 1949 throw invalidValue(cfc,prop,"unsavedValue",str,"null, negative, undefined",data); 1950 //throw new ORMException("invalid value ["+str+"] for attribute [unsavedValue], valid values are [null, negative, undefined]"); 1951 } 1952 } 1953 1954 private static String toString(Component cfc,Property prop,Struct sct, String key, SessionFactoryData data) throws PageException { 1955 return toString(cfc,prop,sct, key, false,data); 1956 } 1957 1958 private static String toString(Component cfc,Property prop,Struct sct, String key, boolean throwErrorWhenNotExist, SessionFactoryData data) throws PageException { 1959 return toString(cfc,prop,sct, CommonUtil.createKey(key), throwErrorWhenNotExist,data); 1960 } 1961 1962 private static String toString(Component cfc,Property prop,Struct sct, Collection.Key key, boolean throwErrorWhenNotExist, SessionFactoryData data) throws PageException { 1963 Object value = sct.get(key,null); 1964 if(value==null) { 1965 if(throwErrorWhenNotExist){ 1966 if(prop==null)throw ExceptionUtil.createException(data,cfc,"attribute ["+key+"] is required",null); 1967 throw ExceptionUtil.createException(data,cfc,"attribute ["+key+"] of property ["+prop.getName()+"] of Component ["+_getCFCName(prop)+"] is required",null); 1968 } 1969 return null; 1970 } 1971 1972 String str=CommonUtil.toString(value,null); 1973 if(str==null) { 1974 if(prop==null) 1975 throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a string",null); 1976 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); 1977 } 1978 return str; 1979 } 1980 1981 private static String _getCFCName(Property prop) { 1982 String owner = prop.getOwnerName(); 1983 return CommonUtil.last(owner,'.'); 1984 } 1985 1986 1987 1988 1989 private static Boolean toBoolean(Component cfc,Struct sct, String key, SessionFactoryData data) throws PageException { 1990 Object value = sct.get(CommonUtil.createKey(key),null); 1991 if(value==null) return null; 1992 1993 Boolean b=CommonUtil.toBoolean(value,null); 1994 if(b==null) throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a boolean",null); 1995 return b; 1996 } 1997 1998 private static Integer toInteger(Component cfc,Struct sct, String key,SessionFactoryData data) throws PageException { 1999 Object value = sct.get(CommonUtil.createKey(key),null); 2000 if(value==null) return null; 2001 2002 Integer i=CommonUtil.toInteger(value,null); 2003 if(i==null) throw ExceptionUtil.createException(data,cfc,"invalid type ["+CommonUtil.toTypeName(value)+"] for attribute ["+key+"], value must be a numeric value",null); 2004 return i; 2005 } 2006 2007 2008} 2009 2010 class PropertyCollection { 2011 private Property[] properties; 2012 private String tableName; 2013 public PropertyCollection(String tableName,Property[] properties) { 2014 this.tableName=tableName; 2015 this.properties=properties; 2016 } 2017 public PropertyCollection(String tableName, java.util.List<Property> properties) { 2018 this.tableName=tableName; 2019 this.properties=properties.toArray(new Property[properties.size()]); 2020 } 2021 public Property[] getProperties() { 2022 return properties; 2023 } 2024 public String getTableName() { 2025 return tableName; 2026 } 2027 2028 }