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