001 package railo.runtime.orm; 002 003 import java.io.IOException; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 007 import org.w3c.dom.Attr; 008 import org.w3c.dom.Element; 009 import org.w3c.dom.NamedNodeMap; 010 011 import railo.commons.digest.MD5; 012 import railo.commons.io.res.Resource; 013 import railo.commons.io.res.util.ResourceUtil; 014 import railo.commons.lang.StringUtil; 015 import railo.runtime.PageContext; 016 import railo.runtime.config.Config; 017 import railo.runtime.config.ConfigWebImpl; 018 import railo.runtime.engine.ThreadLocalPageContext; 019 import railo.runtime.exp.ExpressionException; 020 import railo.runtime.listener.ApplicationContextPro; 021 import railo.runtime.op.Caster; 022 import railo.runtime.op.Decision; 023 import railo.runtime.type.Array; 024 import railo.runtime.type.ArrayImpl; 025 import railo.runtime.type.Collection; 026 import railo.runtime.type.KeyImpl; 027 import railo.runtime.type.List; 028 import railo.runtime.type.Struct; 029 import railo.runtime.type.StructImpl; 030 031 public class ORMConfiguration { 032 public static final int DBCREATE_NONE=0; 033 public static final int DBCREATE_UPDATE=1; 034 public static final int DBCREATE_DROP_CREATE=2; 035 036 public static final Collection.Key AUTO_GEN_MAP = KeyImpl.intern("autogenmap"); 037 public static final Collection.Key CATALOG = KeyImpl.intern("catalog"); 038 public static final Collection.Key CFC_LOCATION = KeyImpl.intern("cfcLocation"); 039 public static final Collection.Key IS_DEFAULT_CFC_LOCATION = KeyImpl.intern("isDefaultCfclocation"); 040 public static final Collection.Key DB_CREATE = KeyImpl.intern("dbCreate"); 041 public static final Collection.Key DIALECT = KeyImpl.intern("dialect"); 042 public static final Collection.Key FLUSH_AT_REQUEST_END = KeyImpl.intern("flushAtRequestEnd"); 043 public static final Collection.Key LOG_SQL = KeyImpl.intern("logSql"); 044 public static final Collection.Key SAVE_MAPPING = KeyImpl.intern("savemapping"); 045 public static final Collection.Key SCHEMA = KeyImpl.intern("schema"); 046 public static final Collection.Key SECONDARY_CACHE_ENABLED = KeyImpl.intern("secondarycacheenabled"); 047 public static final Collection.Key SQL_SCRIPT = KeyImpl.intern("sqlscript"); 048 public static final Collection.Key USE_DB_FOR_MAPPING = KeyImpl.intern("useDBForMapping"); 049 public static final Collection.Key CACHE_CONFIG = KeyImpl.intern("cacheconfig"); 050 public static final Collection.Key CACHE_PROVIDER = KeyImpl.intern("cacheProvider"); 051 public static final Collection.Key ORM_CONFIG = KeyImpl.intern("ormConfig"); 052 public static final Collection.Key EVENT_HANDLING = KeyImpl.intern("eventHandling"); 053 public static final Collection.Key EVENT_HANDLER = KeyImpl.intern("eventHandler"); 054 public static final Collection.Key AUTO_MANAGE_SESSION = KeyImpl.intern("autoManageSession"); 055 public static final Collection.Key SKIP_WITH_ERROR = KeyImpl.intern("skipCFCWithError"); 056 public static final Collection.Key NAMING_STRATEGY = KeyImpl.intern("namingstrategy"); 057 058 059 private boolean autogenmap=true; 060 private String catalog; 061 private Resource[] cfcLocations; 062 private int dbCreate=DBCREATE_NONE; 063 private String dialect; 064 private Boolean eventHandling=null; 065 private boolean flushAtRequestEnd=true; 066 private boolean logSQL; 067 private boolean saveMapping; 068 private String schema; 069 private boolean secondaryCacheEnabled; 070 private Resource sqlScript; 071 private boolean useDBForMapping=true; 072 private Resource cacheConfig; 073 private String cacheProvider; 074 private Resource ormConfig; 075 private String eventHandler; 076 private String namingStrategy; 077 private boolean isDefaultCfcLocation=true; 078 private boolean skipCFCWithError=true; 079 private boolean autoManageSession=true; 080 081 private ORMConfiguration(){ 082 autogenmap=true; 083 dbCreate=DBCREATE_NONE; 084 flushAtRequestEnd=true; 085 useDBForMapping=true; 086 } 087 088 089 090 091 092 093 public static ORMConfiguration load(Config config,ApplicationContextPro ac, Element el, Resource defaultCFCLocation,ORMConfiguration defaultConfig) { 094 return _load(config,ac, new _GetElement(el),defaultCFCLocation,defaultConfig); 095 } 096 097 public static ORMConfiguration load(Config config,ApplicationContextPro ac,Struct settings, Resource defaultCFCLocation,ORMConfiguration defaultConfig) { 098 return _load(config,ac, new _GetStruct(settings),defaultCFCLocation,defaultConfig); 099 } 100 101 private static ORMConfiguration _load(Config config,ApplicationContextPro ac, _Get settings, Resource defaultCFCLocation,ORMConfiguration dc) { 102 103 if(dc==null)dc=new ORMConfiguration(); 104 ORMConfiguration c = dc.duplicate(); 105 c.cfcLocations=defaultCFCLocation==null?new Resource[0]:new Resource[]{defaultCFCLocation}; 106 107 // autogenmap 108 c.autogenmap=Caster.toBooleanValue(settings.get(AUTO_GEN_MAP,dc.autogenmap()),dc.autogenmap()); 109 110 // catalog 111 c.catalog=StringUtil.trim(Caster.toString(settings.get(CATALOG,dc.getCatalog()),dc.getCatalog()),dc.getCatalog()); 112 113 // cfclocation 114 Object obj = settings.get(CFC_LOCATION,null); 115 if(obj!=null){ 116 Resource res; 117 if(!Decision.isArray(obj)){ 118 String list = Caster.toString(obj,null); 119 if(!StringUtil.isEmpty(list)) { 120 obj=List.listToArray(list, ','); 121 } 122 } 123 124 if(Decision.isArray(obj)) { 125 Array arr=Caster.toArray(obj,null); 126 java.util.List<Resource> list=new ArrayList<Resource>(); 127 //c.cfcLocations=new Resource[arr.size()]; 128 Iterator it = arr.valueIterator(); 129 130 while(it.hasNext()){ 131 try { 132 res=toResourceExisting(config,ac,it.next()); 133 if(res!=null) list.add(res); 134 } 135 catch(Throwable t){} 136 } 137 if(list.size()>0){ 138 c.cfcLocations=list.toArray(new Resource[list.size()]); 139 c.isDefaultCfcLocation=false; 140 } 141 } 142 } 143 if(c.cfcLocations == null) 144 c.cfcLocations=defaultCFCLocation==null?new Resource[0]:new Resource[]{defaultCFCLocation}; 145 146 // dbcreate 147 obj = settings.get(DB_CREATE,null); 148 if(obj!=null){ 149 String str = Caster.toString(obj,"").trim().toLowerCase(); 150 c.dbCreate=dbCreateAsInt(str); 151 } 152 153 // dialect 154 c.dialect = StringUtil.trim(Caster.toString(settings.get(DIALECT,dc.getDialect()),dc.getDialect()),dc.getDialect()); 155 156 // namingstrategy 157 c.namingStrategy=Caster.toString(settings.get(NAMING_STRATEGY,dc.namingStrategy()),dc.namingStrategy()); 158 159 // eventHandler 160 c.eventHandler=Caster.toString(settings.get(EVENT_HANDLER,dc.eventHandler()),dc.eventHandler()); 161 162 // eventHandling 163 Boolean b=Caster.toBoolean(settings.get(EVENT_HANDLING,null),null); 164 if(b==null) { 165 if(dc.eventHandling!=null && dc.eventHandling) 166 b=Boolean.TRUE; 167 else 168 b=!StringUtil.isEmpty(c.eventHandler,true); 169 } 170 c.eventHandling=b; 171 172 // flushatrequestend 173 c.flushAtRequestEnd=Caster.toBooleanValue(settings.get(FLUSH_AT_REQUEST_END,dc.flushAtRequestEnd()),dc.flushAtRequestEnd()); 174 175 // logSQL 176 c.logSQL=Caster.toBooleanValue(settings.get(LOG_SQL,dc.logSQL()),dc.logSQL()); 177 178 179 // autoManageSession 180 c.autoManageSession=Caster.toBooleanValue(settings.get(AUTO_MANAGE_SESSION,dc.autoManageSession()),dc.autoManageSession()); 181 182 // skipCFCWithError 183 c.skipCFCWithError=Caster.toBooleanValue(settings.get(SKIP_WITH_ERROR,dc.skipCFCWithError()),dc.skipCFCWithError()); 184 185 // savemapping 186 c.saveMapping=Caster.toBooleanValue(settings.get(SAVE_MAPPING,dc.saveMapping()),dc.saveMapping()); 187 188 // schema 189 c.schema=StringUtil.trim(Caster.toString(settings.get(SCHEMA,dc.getSchema()),dc.getSchema()),dc.getSchema()); 190 191 // secondarycacheenabled 192 c.secondaryCacheEnabled=Caster.toBooleanValue(settings.get(SECONDARY_CACHE_ENABLED,dc.secondaryCacheEnabled()),dc.secondaryCacheEnabled()); 193 194 // sqlscript 195 obj = settings.get(SQL_SCRIPT,null); 196 if(!StringUtil.isEmpty(obj)){ 197 try { 198 c.sqlScript=toRes(config, obj, true); 199 } catch (ExpressionException e) { 200 //print.e(e); 201 } 202 } 203 204 // useDBForMapping 205 c.useDBForMapping=Caster.toBooleanValue(settings.get(USE_DB_FOR_MAPPING,dc.useDBForMapping()),dc.useDBForMapping()); 206 207 // cacheconfig 208 obj = settings.get(CACHE_CONFIG,null); 209 if(!StringUtil.isEmpty(obj)){ 210 try { 211 c.cacheConfig=toRes(config, obj, true); 212 } catch (ExpressionException e) { 213 //print.printST(e); 214 } 215 } 216 217 // cacheprovider 218 c.cacheProvider=StringUtil.trim(Caster.toString(settings.get(CACHE_PROVIDER,dc.getCacheProvider()),dc.getCacheProvider()),dc.getCacheProvider()); 219 220 // ormconfig 221 obj = settings.get(ORM_CONFIG,null); 222 if(!StringUtil.isEmpty(obj)){ 223 try { 224 c.ormConfig=toRes(config, obj, true); 225 } catch (ExpressionException e) { 226 //print.printST(e); 227 } 228 } 229 230 return c; 231 } 232 233 private static Resource toRes(Config config, Object obj, boolean existing) throws ExpressionException { 234 PageContext pc = ThreadLocalPageContext.get(); 235 if(pc!=null)return Caster.toResource(pc, obj, existing); 236 return Caster.toResource(config, obj, existing); 237 } 238 239 private static Resource toResourceExisting(Config config, ApplicationContextPro ac,Object obj) { 240 //Resource root = config.getRootDirectory(); 241 String path = Caster.toString(obj,null); 242 if(StringUtil.isEmpty(path,true)) return null; 243 path=path.trim(); 244 Resource res; 245 PageContext pc = ThreadLocalPageContext.get(); 246 247 // first check relative to application.cfc 248 if(pc!=null) { 249 if(ac==null) ac=(ApplicationContextPro) pc.getApplicationContext(); 250 251 // abs path 252 if(path.startsWith("/")){ 253 ConfigWebImpl cwi=(ConfigWebImpl) config; 254 res=cwi.getPhysicalResourceExisting( 255 pc, 256 ac==null?null:ac.getMappings(), path, 257 false, false, true); 258 if(res!=null && res.isDirectory()) return res; 259 } 260 // real path 261 else { 262 Resource src= ac!=null?ac.getSource():null; 263 if(src!=null) { 264 res=src.getParentResource().getRealResource(path); 265 if(res!=null && res.isDirectory()) return res; 266 } 267 // happens when this is called from within the application.cfc (init) 268 else { 269 res=ResourceUtil.toResourceNotExisting(pc, path); 270 if(res!=null && res.isDirectory()) return res; 271 } 272 } 273 } 274 275 276 277 // then in the webroot 278 res=config.getRootDirectory().getRealResource(path); 279 if(res!=null && res.isDirectory()) return res; 280 281 // then absolute 282 res = ResourceUtil.toResourceNotExisting(config, path); 283 284 if(res!=null && res.isDirectory()) return res; 285 return null; 286 } 287 288 289 290 291 292 293 private ORMConfiguration duplicate() { 294 295 ORMConfiguration other = new ORMConfiguration(); 296 297 298 299 other.autogenmap=autogenmap; 300 other.catalog=catalog; 301 other.cfcLocations=cfcLocations; 302 other.isDefaultCfcLocation=isDefaultCfcLocation; 303 other.dbCreate=dbCreate; 304 other.dialect=dialect; 305 other.eventHandler=eventHandler; 306 other.namingStrategy=namingStrategy; 307 other.eventHandling=eventHandling; 308 other.flushAtRequestEnd=flushAtRequestEnd; 309 other.logSQL=logSQL; 310 other.saveMapping=saveMapping; 311 other.schema=schema; 312 other.secondaryCacheEnabled=secondaryCacheEnabled; 313 other.sqlScript=sqlScript; 314 other.useDBForMapping=useDBForMapping; 315 other.cacheConfig=cacheConfig; 316 other.cacheProvider=cacheProvider; 317 other.ormConfig=ormConfig; 318 other.autoManageSession=autoManageSession; 319 other.skipCFCWithError=skipCFCWithError; 320 return other; 321 } 322 323 public String hash() { 324 325 String data=autogenmap+":"+catalog+":"+isDefaultCfcLocation 326 +":"+dbCreate+":"+dialect+":"+eventHandling+":"+namingStrategy+":"+eventHandler+":"+flushAtRequestEnd+":"+logSQL+":"+autoManageSession+":"+skipCFCWithError+":"+saveMapping+":"+schema+":"+secondaryCacheEnabled+":"+ 327 useDBForMapping+":"+cacheProvider 328 329 +":"+toStr(cfcLocations)+":"+toStr(sqlScript)+":"+toStr(cacheConfig)+":"+toStr(ormConfig) 330 ; 331 332 try { 333 return MD5.getDigestAsString(data); 334 } catch (IOException e) { 335 return null; 336 } 337 } 338 339 340 341 342 343 private String toStr(Resource res) { 344 if(res==null) return ""; 345 return res.getAbsolutePath(); 346 } 347 private String toStr(Resource[] reses) { 348 if(reses==null) return ""; 349 StringBuilder sb=new StringBuilder(); 350 for(int i=0;i<reses.length;i++){ 351 sb.append(toStr(reses[i])); 352 } 353 return sb.toString(); 354 } 355 356 357 358 359 360 361 /** 362 * @return the autogenmap 363 */ 364 public boolean autogenmap() { 365 return autogenmap; 366 } 367 368 /** 369 * @return the catalog 370 */ 371 public String getCatalog() { 372 return catalog; 373 } 374 375 /** 376 * @return the cfcLocation 377 */ 378 public Resource[] getCfcLocations() { 379 return cfcLocations; 380 } 381 public boolean isDefaultCfcLocation() { 382 return isDefaultCfcLocation; 383 } 384 385 /** 386 * @return the dbCreate 387 */ 388 public int getDbCreate() { 389 return dbCreate; 390 } 391 392 /** 393 * @return the dialect 394 */ 395 public String getDialect() { 396 return dialect; 397 } 398 399 /** 400 * @return the eventHandling 401 */ 402 public boolean eventHandling() { 403 return eventHandling==null?false:eventHandling; 404 } 405 406 public String eventHandler() { 407 return eventHandler; 408 } 409 410 public String namingStrategy() { 411 return namingStrategy; 412 } 413 414 415 416 /** 417 * @return the flushAtRequestEnd 418 */ 419 public boolean flushAtRequestEnd() { 420 return flushAtRequestEnd; 421 } 422 423 /** 424 * @return the logSQL 425 */ 426 public boolean logSQL() { 427 return logSQL; 428 } 429 430 /** 431 * @return the saveMapping 432 */ 433 public boolean saveMapping() { 434 return saveMapping; 435 } 436 437 /** 438 * @return the schema 439 */ 440 public String getSchema() { 441 return schema; 442 } 443 444 /** 445 * @return the secondaryCacheEnabled 446 */ 447 public boolean secondaryCacheEnabled() { 448 return secondaryCacheEnabled; 449 } 450 451 /** 452 * @return the sqlScript 453 */ 454 public Resource getSqlScript() { 455 return sqlScript; 456 } 457 458 /** 459 * @return the useDBForMapping 460 */ 461 public boolean useDBForMapping() { 462 return useDBForMapping; 463 } 464 465 /** 466 * @return the cacheConfig 467 */ 468 public Resource getCacheConfig() { 469 return cacheConfig; 470 } 471 472 /** 473 * @return the cacheProvider 474 */ 475 public String getCacheProvider() { 476 return cacheProvider; 477 } 478 479 /** 480 * @return the ormConfig 481 */ 482 public Resource getOrmConfig() { 483 return ormConfig; 484 } 485 486 public boolean skipCFCWithError() { 487 return skipCFCWithError; 488 } 489 public boolean autoManageSession() { 490 return autoManageSession; 491 } 492 493 494 495 496 public Object toStruct() { 497 498 Resource[] locs = getCfcLocations(); 499 Array arrLocs=new ArrayImpl(); 500 if(locs!=null)for(int i=0;i<locs.length;i++){ 501 arrLocs.appendEL(getAbsolutePath(locs[i])); 502 } 503 Struct sct=new StructImpl(); 504 sct.setEL(AUTO_GEN_MAP,this.autogenmap()); 505 sct.setEL(CATALOG,StringUtil.emptyIfNull(getCatalog())); 506 sct.setEL(CFC_LOCATION,arrLocs); 507 sct.setEL(IS_DEFAULT_CFC_LOCATION,isDefaultCfcLocation()); 508 sct.setEL(DB_CREATE,dbCreateAsString(getDbCreate())); 509 sct.setEL(DIALECT,StringUtil.emptyIfNull(getDialect())); 510 sct.setEL(EVENT_HANDLING,eventHandling()); 511 sct.setEL(EVENT_HANDLER,eventHandler()); 512 sct.setEL(NAMING_STRATEGY,namingStrategy()); 513 sct.setEL(FLUSH_AT_REQUEST_END,flushAtRequestEnd()); 514 sct.setEL(LOG_SQL,logSQL()); 515 sct.setEL(SAVE_MAPPING,saveMapping()); 516 sct.setEL(SCHEMA,StringUtil.emptyIfNull(getSchema())); 517 sct.setEL(SECONDARY_CACHE_ENABLED,secondaryCacheEnabled()); 518 sct.setEL(SQL_SCRIPT,StringUtil.toStringEmptyIfNull(getSqlScript())); 519 sct.setEL(USE_DB_FOR_MAPPING,useDBForMapping()); 520 sct.setEL(CACHE_CONFIG,getAbsolutePath(getCacheConfig())); 521 sct.setEL(CACHE_PROVIDER,StringUtil.emptyIfNull(getCacheProvider())); 522 sct.setEL(ORM_CONFIG,getAbsolutePath(getOrmConfig())); 523 524 525 return sct; 526 } 527 528 529 private static String getAbsolutePath(Resource res) { 530 if(res==null )return ""; 531 return res.getAbsolutePath(); 532 } 533 534 535 536 537 538 539 public static int dbCreateAsInt(String dbCreate) { 540 if(dbCreate==null)dbCreate=""; 541 else dbCreate=dbCreate.trim().toLowerCase(); 542 543 if("update".equals(dbCreate))return DBCREATE_UPDATE; 544 if("dropcreate".equals(dbCreate))return DBCREATE_DROP_CREATE; 545 if("drop-create".equals(dbCreate))return DBCREATE_DROP_CREATE; 546 547 return DBCREATE_NONE; 548 } 549 550 551 552 553 public static String dbCreateAsString(int dbCreate) { 554 555 switch(dbCreate){ 556 case DBCREATE_DROP_CREATE: return "dropcreate"; 557 case DBCREATE_UPDATE: return "update"; 558 } 559 560 return "none"; 561 } 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 } 579 580 interface _Get { 581 public Object get(Collection.Key name,Object defaultValue); 582 } 583 584 class _GetStruct implements _Get { 585 586 private Struct sct; 587 public _GetStruct(Struct sct){ 588 this.sct=sct; 589 } 590 591 public Object get(Collection.Key name,Object defaultValue){ 592 return sct.get(name,defaultValue); 593 } 594 595 public String toString(){ 596 return "_GetStruct:"+sct.toString(); 597 } 598 } 599 600 class _GetElement implements _Get { 601 602 private Element el; 603 public _GetElement(Element el){ 604 this.el=el; 605 } 606 public Object get(Collection.Key name,Object defaultValue){ 607 String value=_get(name.getString()); 608 if(value==null)value = _get(StringUtil.camelToHypenNotation(name.getString())); 609 if(value==null)value = _get(name.getLowerString()); 610 if(value==null){ 611 NamedNodeMap map = el.getAttributes(); 612 int len=map.getLength(); 613 Attr attr; 614 String n; 615 for(int i=0;i<len;i++){ 616 attr=(Attr) map.item(i); 617 n=attr.getName(); 618 n=StringUtil.replace(n, "-", "", false).toLowerCase(); 619 if(n.equalsIgnoreCase(name.getLowerString())) return attr.getValue(); 620 } 621 622 } 623 624 if(value==null) return defaultValue; 625 return value; 626 } 627 628 private String _get(String name) { 629 if(el.hasAttribute(name)) return el.getAttribute(name); 630 return null; 631 } 632 } 633