001 package railo.runtime.orm.hibernate; 002 003 import java.sql.Types; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.List; 007 008 import org.hibernate.metadata.ClassMetadata; 009 import org.hibernate.type.Type; 010 011 import railo.commons.lang.StringUtil; 012 import railo.commons.lang.types.RefBoolean; 013 import railo.runtime.Component; 014 import railo.runtime.ComponentPro; 015 import railo.runtime.ComponentScope; 016 import railo.runtime.PageContext; 017 import railo.runtime.component.Property; 018 import railo.runtime.db.SQLCaster; 019 import railo.runtime.db.SQLItemImpl; 020 import railo.runtime.engine.ThreadLocalPageContext; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.op.Caster; 023 import railo.runtime.op.Decision; 024 import railo.runtime.orm.ORMEngine; 025 import railo.runtime.orm.ORMException; 026 import railo.runtime.type.Array; 027 import railo.runtime.type.ArrayImpl; 028 import railo.runtime.type.Collection; 029 import railo.runtime.type.Collection.Key; 030 import railo.runtime.type.KeyImpl; 031 import railo.runtime.type.Query; 032 import railo.runtime.type.QueryImpl; 033 import railo.runtime.type.Struct; 034 import railo.runtime.type.cfc.ComponentAccess; 035 import railo.runtime.type.util.ArrayUtil; 036 import railo.runtime.type.util.ComponentUtil; 037 import railo.runtime.type.util.QueryUtil; 038 039 public class HibernateCaster { 040 041 private static final int NULL = -178696; 042 private static final Key ENTITY_NAME = KeyImpl.intern("entityname"); 043 /*public static Component toCFML(PageContext pc,Map map, Component cfc) throws PageException { 044 if(map instanceof ComponentPro) return (Component) map; 045 ComponentPro ci = ComponentUtil.toComponentPro(cfc); 046 ComponentScope scope = ci.getComponentScope(); 047 048 map.remove("$type$"); 049 050 Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); 051 Map.Entry<String, Object> entry; 052 while(it.hasNext()){ 053 entry=it.next(); 054 scope.setEL(entry.getKey(), toCFML(pc,entry.getValue())); 055 } 056 return cfc; 057 }*/ 058 059 public static Object toCFML(Object src) { 060 if(src==null) return null; 061 if(src instanceof Collection) return src; 062 063 if(src instanceof List){ 064 return toCFML((List) src); 065 } 066 /*if(src instanceof Map){ 067 return toCFML(pc,(Map) src); 068 }*/ 069 return src; 070 } 071 072 public static Array toCFML(List src) { 073 int size=src.size(); 074 075 Array trg = new ArrayImpl(); 076 for(int i=0;i<size;i++) { 077 trg.setEL(i+1,toCFML(src.get(i))); 078 } 079 return trg; 080 } 081 082 /*public static Object toCFML(PageContext pc,Map src) throws PageException { 083 084 Object type =src.remove("$type$"); 085 if(type instanceof String){ 086 087 Component cfc = toComponent(pc, (String)type); 088 return toCFML(pc,src, cfc); 089 } 090 091 092 Iterator<Map.Entry<String, Object>> it = src.entrySet().iterator(); 093 Struct trg=new StructImpl(); 094 Map.Entry<String, Object> entry; 095 while(it.hasNext()){ 096 entry=it.next(); 097 trg.setEL(entry.getKey(),toCFML(pc,entry.getValue())); 098 } 099 return trg; 100 }*/ 101 102 103 104 public static String getEntityName(Component cfc) { 105 106 String name=null; 107 try { 108 ComponentAccess cfca = ComponentUtil.toComponentAccess(cfc); 109 name=Caster.toString(cfca.getMetaStructItem(ENTITY_NAME),null); 110 } 111 catch (Throwable t) { 112 try { 113 Struct md = cfc.getMetaData(ThreadLocalPageContext.get()); 114 name = Caster.toString(md.get(ENTITY_NAME),null); 115 116 }catch (PageException e) {} 117 } 118 119 if(!StringUtil.isEmpty(name)) { 120 return name; 121 } 122 return getName(cfc); 123 124 125 } 126 127 private static String getName(Component cfc) { 128 String name=null; 129 // MUSTMUST cfc.getName() should return the real case, this should not be needed 130 ComponentPro cfcp = ComponentUtil.toComponentPro(cfc,null); 131 if(cfcp!=null){ 132 name = cfcp.getPageSource().getDisplayPath(); 133 name=railo.runtime.type.List.last(name, "\\/",true); 134 int index=name.lastIndexOf('.'); 135 name= name.substring(0,index); 136 return name; 137 } 138 //////////////////////// 139 140 return cfc.getName(); 141 } 142 143 public static int cascade(HibernateORMEngine engine,String cascade) throws ORMException { 144 int c=cascade(cascade,-1); 145 if(c!=-1) return c; 146 throw new HibernateException(engine,"invalid cascade defintion ["+cascade+"], valid values are [all,all-delete-orphan,delete,delete-orphan,refresh,save-update]"); 147 } 148 149 public static int cascade(String cascade, int defaultValue) { 150 cascade=cascade.trim().toLowerCase(); 151 if("all".equals(cascade)) return HibernateConstants.CASCADE_ALL; 152 153 if("save-update".equals(cascade)) return HibernateConstants.CASCADE_SAVE_UPDATE; 154 if("save_update".equals(cascade)) return HibernateConstants.CASCADE_SAVE_UPDATE; 155 if("saveupdate".equals(cascade)) return HibernateConstants.CASCADE_SAVE_UPDATE; 156 157 if("delete".equals(cascade)) return HibernateConstants.CASCADE_DELETE; 158 159 if("delete-orphan".equals(cascade)) return HibernateConstants.CASCADE_DELETE_ORPHAN; 160 if("delete_orphan".equals(cascade)) return HibernateConstants.CASCADE_DELETE_ORPHAN; 161 if("deleteorphan".equals(cascade)) return HibernateConstants.CASCADE_DELETE_ORPHAN; 162 163 if("all-delete-orphan".equals(cascade)) return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN; 164 if("all_delete_orphan".equals(cascade)) return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN; 165 if("alldeleteorphan".equals(cascade)) return HibernateConstants.CASCADE_ALL_DELETE_ORPHAN; 166 167 if("refresh".equals(cascade)) return HibernateConstants.REFRESH; 168 169 return defaultValue; 170 } 171 172 public static int collectionType(HibernateORMEngine engine,String strCollectionType) throws ORMException { 173 int ct=collectionType(strCollectionType, -1); 174 if(ct!=-1) return ct; 175 throw new ORMException(engine,"invalid collectionType defintion ["+strCollectionType+"], valid values are [array,struct]"); 176 } 177 public static int collectionType(String strCollectionType, int defaultValue) { 178 strCollectionType=strCollectionType.trim().toLowerCase(); 179 if("struct".equals(strCollectionType)) return HibernateConstants.COLLECTION_TYPE_STRUCT; 180 if("array".equals(strCollectionType)) return HibernateConstants.COLLECTION_TYPE_ARRAY; 181 182 return defaultValue; 183 } 184 185 public static String toHibernateType(ColumnInfo info, String type, String defaultValue) { 186 187 // no type defined 188 if(StringUtil.isEmpty(type,true)) { 189 return HibernateCaster.toHibernateType(info,defaultValue); 190 } 191 192 // type defined 193 String tmp=HibernateCaster.toHibernateType(type,null); 194 if(tmp!=null) return tmp; 195 196 if(info!=null){ 197 tmp=HibernateCaster.toHibernateType(info,defaultValue); 198 //ORMUtil.printError("type ["+type+"] is not a valid Hibernate type. Use instead type ["+tmp+"]", engine); 199 return tmp; 200 } 201 //throw new ORMException("type ["+type+"] is not a valid Hibernate type."); 202 return defaultValue; 203 204 205 } 206 207 public static int toSQLType(String type,int defaultValue) { 208 type=type.trim().toLowerCase(); 209 type=toHibernateType(type,type); 210 if("long".equals(type)) return Types.BIGINT; 211 if("binary".equals(type)) return Types.BINARY; 212 if("boolean".equals(type)) return Types.BIT; 213 if("blob".equals(type)) return Types.BLOB; 214 if("boolean".equals(type)) return Types.BOOLEAN; 215 if("character".equals(type)) return Types.CHAR; 216 if("clob".equals(type)) return Types.CLOB; 217 if("date".equals(type)) return Types.DATE; 218 if("big_decimal".equals(type)) return Types.DECIMAL; 219 if("big_integer".equals(type)) return Types.NUMERIC; 220 if("double".equals(type)) return Types.DOUBLE; 221 if("float".equals(type)) return Types.FLOAT; 222 if("integer".equals(type)) return Types.INTEGER; 223 if("binary".equals(type)) return Types.VARBINARY; 224 if("string".equals(type)) return Types.VARCHAR; 225 if("short".equals(type)) return Types.SMALLINT; 226 if("time".equals(type)) return Types.TIME; 227 if("timestamp".equals(type)) return Types.TIMESTAMP; 228 if("byte".equals(type)) return Types.TINYINT; 229 230 return defaultValue; 231 } 232 233 public static String toHibernateType(ColumnInfo info, String defaultValue) { 234 if(info==null)return defaultValue; 235 236 String rtn = toHibernateType(info.getType(),info.getSize(), null); 237 if(rtn!=null) return rtn; 238 return toHibernateType(info.getTypeName(),defaultValue); 239 } 240 241 public static String toHibernateType(int type, int size, String defaultValue) { 242 // MUST do better 243 switch(type){ 244 case Types.ARRAY: return ""; 245 case Types.BIGINT: return "long"; 246 case Types.BINARY: return "binary"; 247 case Types.BIT: return "boolean"; 248 case Types.BLOB: return "blob"; 249 case Types.BOOLEAN: return "boolean"; 250 case Types.CHAR: 251 return "string"; 252 //if(size>1) return "string"; 253 //return "character"; 254 case Types.CLOB: return "clob"; 255 //case Types.DATALINK: return ""; 256 case Types.DATE: return "date"; 257 case Types.DECIMAL: return "big_decimal"; 258 //case Types.DISTINCT: return ""; 259 case Types.DOUBLE: return "double"; 260 case Types.FLOAT: return "float"; 261 case Types.INTEGER: return "integer"; 262 //case Types.JAVA_OBJECT: return ""; 263 case Types.LONGVARBINARY: return "binary"; 264 case Types.LONGVARCHAR: return "string"; 265 //case Types.NULL: return ""; 266 case Types.NUMERIC: return "big_decimal"; 267 //case Types.OTHER: return ""; 268 //case Types.REAL: return ""; 269 //case Types.REF: return ""; 270 case Types.SMALLINT: return "short"; 271 //case Types.STRUCT: return ""; 272 case Types.TIME: return "time"; 273 case Types.TIMESTAMP: return "timestamp"; 274 case Types.TINYINT: return "byte"; 275 case Types.VARBINARY: return "binary"; 276 case Types.NVARCHAR: return "string"; 277 case Types.VARCHAR: return "string"; 278 } 279 return defaultValue; 280 } 281 282 public static String toHibernateType(HibernateORMEngine engine,String type) throws ORMException { 283 String res=toHibernateType(type, null); 284 if(res==null) throw new ORMException(engine,"the type ["+type+"] is not supported"); 285 return res; 286 } 287 288 289 // calendar_date: A type mapping for a Calendar object that represents a date 290 //calendar: A type mapping for a Calendar object that represents a datetime. 291 public static String toHibernateType(String type, String defaultValue) { 292 type=type.trim().toLowerCase(); 293 type=StringUtil.replace(type, "java.lang.", "", true); 294 type=StringUtil.replace(type, "java.util.", "", true); 295 type=StringUtil.replace(type, "java.sql.", "", true); 296 297 // return same value 298 if("long".equals(type)) return type; 299 if("binary".equals(type)) return type; 300 if("boolean".equals(type)) return type; 301 if("blob".equals(type)) return "binary"; 302 if("boolean".equals(type)) return type; 303 if("character".equals(type)) return type; 304 if("clob".equals(type)) return "text"; 305 if("date".equals(type)) return type; 306 if("big_decimal".equals(type)) return type; 307 if("double".equals(type)) return type; 308 if("float".equals(type)) return type; 309 if("integer".equals(type)) return type; 310 if("binary".equals(type)) return type; 311 if("string".equals(type)) return type; 312 if("big_integer".equals(type)) return type; 313 if("short".equals(type)) return type; 314 if("time".equals(type)) return type; 315 if("timestamp".equals(type)) return type; 316 if("byte".equals(type)) return type; 317 if("binary".equals(type)) return type; 318 if("string".equals(type)) return type; 319 if("text".equals(type)) return type; 320 if("calendar".equals(type)) return type; 321 if("calendar_date".equals(type)) return type; 322 if("locale".equals(type)) return type; 323 if("timezone".equals(type)) return type; 324 if("currency".equals(type)) return type; 325 326 if("imm_date".equals(type)) return type; 327 if("imm_time".equals(type)) return type; 328 if("imm_timestamp".equals(type)) return type; 329 if("imm_calendar".equals(type)) return type; 330 if("imm_calendar_date".equals(type)) return type; 331 if("imm_serializable".equals(type)) return type; 332 if("imm_binary".equals(type)) return type; 333 334 // return different value 335 if("bigint".equals(type)) return "long"; 336 if("bit".equals(type)) return "boolean"; 337 338 if("int".equals(type)) return "integer"; 339 if("char".equals(type)) return "character"; 340 341 if("bool".equals(type)) return "boolean"; 342 if("yes-no".equals(type)) return "yes_no"; 343 if("yesno".equals(type)) return "yes_no"; 344 if("yes_no".equals(type)) return "yes_no"; 345 if("true-false".equals(type)) return "true_false"; 346 if("truefalse".equals(type)) return "true_false"; 347 if("true_false".equals(type)) return "true_false"; 348 if("varchar".equals(type)) return "string"; 349 if("big-decimal".equals(type)) return "big_decimal"; 350 if("bigdecimal".equals(type)) return "big_decimal"; 351 if("java.math.bigdecimal".equals(type)) return "big_decimal"; 352 if("big-integer".equals(type)) return "big_integer"; 353 if("biginteger".equals(type)) return "big_integer"; 354 if("bigint".equals(type)) return "big_integer"; 355 if("java.math.biginteger".equals(type)) return "big_integer"; 356 if("byte[]".equals(type)) return "binary"; 357 if("serializable".equals(type)) return "serializable"; 358 359 if("datetime".equals(type)) return "timestamp"; 360 if("numeric".equals(type)) return "double"; 361 if("number".equals(type)) return "double"; 362 if("numeric".equals(type)) return "double"; 363 if("char".equals(type)) return "character"; 364 if("nchar".equals(type)) return "character"; 365 if("decimal".equals(type)) return "double"; 366 if("eurodate".equals(type)) return "timestamp"; 367 if("usdate".equals(type)) return "timestamp"; 368 if("int".equals(type)) return "integer"; 369 if("varchar".equals(type)) return "string"; 370 if("nvarchar".equals(type)) return "string"; 371 372 return defaultValue; 373 374 // FUTURE 375 /* 376 377 add support for 378 - any, object,other 379 380 add support for custom types https://issues.jboss.org/browse/RAILO-1341 381 - array 382 - base64 383 - guid 384 - memory 385 - node, xml 386 - query 387 - struct 388 - uuid 389 - variablename, variable_name 390 - variablestring, variable_string 391 392 */ 393 394 } 395 396 /** 397 * translate CFMl specific types to Hibernate/SQL specific types 398 * @param engine 399 * @param ci 400 * @param value 401 * @return 402 * @throws PageException 403 */ 404 public static Object toSQL(HibernateORMEngine engine,ColumnInfo ci, Object value, RefBoolean isArray) throws PageException { 405 return toSQL(engine, ci.getType(), value,isArray); 406 } 407 408 /** 409 * translate CFMl specific types to Hibernate/SQL specific types 410 * @param engine 411 * @param type 412 * @param value 413 * @return 414 * @throws PageException 415 */ 416 public static Object toSQL(HibernateORMEngine engine,Type type, Object value, RefBoolean isArray) throws PageException { 417 int t = toSQLType(type.getName(), Types.OTHER); 418 if(t==Types.OTHER) return value; 419 return toSQL(engine, t, value,isArray); 420 } 421 422 /** 423 * translate CFMl specific type to SQL specific types 424 * @param engine 425 * @param sqlType 426 * @param value 427 * @return 428 * @throws PageException 429 */ 430 private static Object toSQL(HibernateORMEngine engine,int sqlType, Object value, RefBoolean isArray) throws PageException { 431 if(isArray!=null)isArray.setValue(false); 432 SQLItemImpl item = new SQLItemImpl(value,sqlType); 433 try{ 434 return SQLCaster.toSqlType(item); 435 } 436 catch(PageException pe){ 437 // pherhaps it is a array of this type 438 if(isArray!=null && Decision.isArray(value)) { 439 Object[] src = Caster.toNativeArray(value); 440 ArrayList<Object> trg = new ArrayList<Object>(); 441 for(int i=0;i<src.length;i++){ 442 try{ 443 trg.add(SQLCaster.toSqlType(new SQLItemImpl(src[i],sqlType))); 444 } 445 catch(PageException inner){ 446 throw pe; 447 } 448 } 449 isArray.setValue(true); 450 return ArrayUtil.toArray(trg); 451 452 } 453 throw pe; 454 } 455 456 } 457 458 459 public static railo.runtime.type.Query toQuery(PageContext pc,HibernateORMSession session, Object obj, String name) throws PageException { 460 Query qry=null; 461 // a single entity 462 if(!Decision.isArray(obj)){ 463 qry= toQuery(pc,session,ComponentUtil.toComponentPro(HibernateCaster.toComponent(obj)),name,null,1,1); 464 } 465 466 // a array of entities 467 else { 468 Array arr=Caster.toArray(obj); 469 int len=arr.size(); 470 if(len>0) { 471 Iterator it = arr.valueIterator(); 472 int row=1; 473 while(it.hasNext()){ 474 qry=toQuery(pc,session,ComponentUtil.toComponentPro(HibernateCaster.toComponent(it.next())),name,qry,len,row++); 475 } 476 } 477 else 478 qry=new QueryImpl(new Collection.Key[0],0,"orm"); 479 } 480 481 if(qry==null) { 482 if(!StringUtil.isEmpty(name)) 483 throw new ORMException(session.getEngine(),"there is no entity inheritance that match the name ["+name+"]"); 484 throw new ORMException(session.getEngine(),"cannot create query"); 485 } 486 return qry; 487 } 488 489 private static Query toQuery(PageContext pc,HibernateORMSession session,ComponentPro cfc, String entityName,Query qry, int rowcount, int row) throws PageException { 490 // inheritance mapping 491 if(!StringUtil.isEmpty(entityName)){ 492 //String cfcName = toComponentName(HibernateCaster.toComponent(pc, entityName)); 493 return inheritance(pc,session,cfc,qry, entityName); 494 } 495 return populateQuery(pc,session,cfc,qry); 496 } 497 498 499 500 501 private static Query populateQuery(PageContext pc,HibernateORMSession session,ComponentPro cfc,Query qry) throws PageException { 502 Property[] properties = cfc.getProperties(true); 503 ComponentScope scope = cfc.getComponentScope(); 504 HibernateORMEngine engine=(HibernateORMEngine) session.getEngine(); 505 506 // init 507 if(qry==null){ 508 ClassMetadata md = ((HibernateORMEngine)session.getEngine()).getSessionFactory(pc).getClassMetadata(getEntityName(cfc)); 509 //Struct columnsInfo= engine.getTableInfo(session.getDatasourceConnection(),toEntityName(engine, cfc),session.getEngine()); 510 Array names=new ArrayImpl(); 511 Array types=new ArrayImpl(); 512 String name; 513 //ColumnInfo ci; 514 int t; 515 for(int i=0;i<properties.length;i++){ 516 name=HibernateUtil.validateColumnName(md, properties[i].getName(),null); 517 //if(columnsInfo!=null)ci=(ColumnInfo) columnsInfo.get(name,null); 518 //else ci=null; 519 names.append(name); 520 if(name!=null){ 521 522 t=HibernateCaster.toSQLType(HibernateUtil.getPropertyType(md, name).getName(), NULL); 523 if(t==NULL) 524 types.append("object"); 525 else 526 types.append(SQLCaster.toStringType(t)); 527 } 528 else 529 types.append("object"); 530 } 531 532 qry=new QueryImpl(names,types,0,getEntityName(cfc)); 533 534 } 535 // check 536 else if(engine.getMode() == ORMEngine.MODE_STRICT){ 537 if(!qry.getName().equals(getEntityName(cfc))) 538 throw new ORMException(session.getEngine(),"can only merge entities of the same kind to a query"); 539 } 540 541 // populate 542 Key[] names=QueryUtil.getColumnNames(qry); 543 544 545 int row=qry.addRow(); 546 for(int i=0;i<names.length;i++){ 547 qry.setAtEL(names[i], row, scope.get(names[i],null)); 548 } 549 return qry; 550 } 551 552 553 554 555 private static Query inheritance(PageContext pc,HibernateORMSession session,ComponentPro cfc,Query qry, String entityName) throws PageException { 556 Property[] properties = cfc.getProperties(true); 557 ComponentScope scope = cfc.getComponentScope(); 558 String name; 559 Object value; 560 ComponentPro child; 561 Array arr; 562 for(int i=0;i<properties.length;i++){ 563 name=properties[i].getName(); 564 value=scope.get(name,null); 565 if(value instanceof ComponentPro){ 566 qry=inheritance(pc,session,qry,cfc,(ComponentPro) value,entityName); 567 } 568 else if(Decision.isArray(value)){ 569 arr = Caster.toArray(value); 570 Iterator it = arr.valueIterator(); 571 while(it.hasNext()){ 572 value=it.next(); 573 if(value instanceof ComponentPro){ 574 qry=inheritance(pc,session,qry,cfc,(ComponentPro) value,entityName); 575 } 576 } 577 } 578 } 579 return qry; 580 } 581 582 583 584 585 private static Query inheritance(PageContext pc,HibernateORMSession session,Query qry,ComponentPro parent,ComponentPro child,String entityName) throws PageException { 586 if(getEntityName(child).equalsIgnoreCase(entityName)) 587 return populateQuery(pc,session,child,qry); 588 return inheritance(pc,session,child, qry, entityName);// MUST geh ACF auch so tief? 589 } 590 591 592 /** 593 * return the full name (package and name) of a component 594 * @param cfc 595 * @return 596 */ 597 public static String toComponentName(Component cfc) { 598 return ((ComponentPro)cfc).getPageSource().getComponentName(); 599 } 600 601 public static Component toComponent(Object obj) throws PageException { 602 return Caster.toComponent(obj); 603 } 604 605 606 /*public static Component toComponent(PageContext pc, Object obj) throws PageException { 607 if(obj instanceof String) 608 return toComponent(pc, (String)obj); 609 return Caster.toComponent(obj); 610 }*/ 611 /*public static Component toComponent(PageContext pc, String name) throws PageException { 612 // MUST muss �ber cfcs kommen oder neues init machen 613 return CreateObject.doComponent(pc, name); 614 }*/ 615 }