001 package railo.runtime.component; 002 003 import java.util.Map; 004 005 import javax.servlet.jsp.tagext.BodyContent; 006 007 import railo.print; 008 import railo.commons.io.res.Resource; 009 import railo.commons.io.res.filter.DirectoryResourceFilter; 010 import railo.commons.io.res.filter.ExtensionResourceFilter; 011 import railo.commons.io.res.filter.OrResourceFilter; 012 import railo.commons.io.res.filter.ResourceFilter; 013 import railo.commons.lang.StringUtil; 014 import railo.commons.lang.types.RefBoolean; 015 import railo.runtime.ComponentImpl; 016 import railo.runtime.ComponentPage; 017 import railo.runtime.ComponentPro; 018 import railo.runtime.InterfaceImpl; 019 import railo.runtime.InterfacePage; 020 import railo.runtime.Mapping; 021 import railo.runtime.MappingImpl; 022 import railo.runtime.Page; 023 import railo.runtime.PageContext; 024 import railo.runtime.PageContextImpl; 025 import railo.runtime.PagePlus; 026 import railo.runtime.PageSource; 027 import railo.runtime.PageSourceImpl; 028 import railo.runtime.config.ConfigImpl; 029 import railo.runtime.debug.DebugEntry; 030 import railo.runtime.exp.ApplicationException; 031 import railo.runtime.exp.ExpressionException; 032 import railo.runtime.exp.PageException; 033 import railo.runtime.listener.ApplicationContextPro; 034 import railo.runtime.op.Caster; 035 import railo.runtime.writer.BodyContentUtil; 036 037 public class ComponentLoader { 038 039 040 private static final ResourceFilter DIR_OR_EXT=new OrResourceFilter(new ResourceFilter[]{DirectoryResourceFilter.FILTER,new ExtensionResourceFilter(".cfc")}); 041 042 public static ComponentImpl loadComponent(PageContext pc,String rawPath, Boolean searchLocal, Boolean searchRoot) throws PageException { 043 return (ComponentImpl)load(pc, rawPath, searchLocal, searchRoot,null,false); 044 } 045 046 public static InterfaceImpl loadInterface(PageContext pc,String rawPath, Map interfaceUDFs) throws PageException { 047 return (InterfaceImpl)load(pc, rawPath, Boolean.TRUE, Boolean.TRUE,interfaceUDFs,false); 048 } 049 050 public static PagePlus loadPage(PageContext pc,String rawPath, Boolean searchLocal, Boolean searchRoot) throws PageException { 051 return (PagePlus)load(pc, rawPath, searchLocal, searchRoot,null,true); 052 } 053 054 055 private static Object load(PageContext pc,String rawPath, Boolean searchLocal, Boolean searchRoot, Map interfaceUDFs, boolean returnPage) throws PageException { 056 ConfigImpl config=(ConfigImpl) pc.getConfig(); 057 boolean doCache=config.useComponentPathCache(); 058 059 //print.o(rawPath); 060 //app-String appName=pc.getApplicationContext().getName(); 061 rawPath=rawPath.trim().replace('\\','/'); 062 String path=(rawPath.indexOf("./")==-1)?rawPath.replace('.','/'):rawPath; 063 String pathWithCFC=path.concat(".cfc"); 064 boolean isRealPath=!StringUtil.startsWith(pathWithCFC,'/'); 065 PageSource currPS = pc.getCurrentPageSource(); 066 Page currP=((PageSourceImpl)currPS).loadPage(pc,pc.getConfig(),null); 067 068 PageSource ps=null; 069 Page page=null; 070 PagePlus pp=(currP instanceof PagePlus)?(PagePlus) currP:null; 071 072 if(searchLocal==null) 073 searchLocal=Caster.toBoolean(config.getComponentLocalSearch()); 074 if(searchRoot==null) 075 searchRoot=Caster.toBoolean(config.getComponentRootSearch()); 076 077 //boolean searchLocal=config.getComponentLocalSearch(); 078 // CACHE 079 // check local in cache 080 String localCacheName=null; 081 if(searchLocal && isRealPath){ 082 localCacheName=currPS.getDisplayPath().replace('\\', '/'); 083 localCacheName=localCacheName.substring(0,localCacheName.lastIndexOf('/')+1).concat(pathWithCFC); 084 if(doCache){ 085 page=config.getCachedPage(pc, localCacheName); 086 if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 087 } 088 } 089 090 // check import cache 091 if(doCache && isRealPath){ 092 ImportDefintion impDef = config.getComponentDefaultImport(); 093 ImportDefintion[] impDefs=pp==null?new ImportDefintion[0]:pp.getImportDefintions(); 094 int i=-1; 095 do{ 096 097 if(impDef.isWildcard() || impDef.getName().equalsIgnoreCase(path)){ 098 page=config.getCachedPage(pc, "import:"+impDef.getPackageAsPath()+pathWithCFC); 099 if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 100 101 //app-page=config.getCachedPage(pc, "import:"+appName+":"+impDef.getPackageAsPath()+pathWithCFC); 102 //app-if(page!=null) return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 103 } 104 impDef=++i<impDefs.length?impDefs[i]:null; 105 } 106 while(impDef!=null); 107 } 108 109 if(doCache) { 110 // check global in cache 111 page=config.getCachedPage(pc, pathWithCFC); 112 if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 113 114 // get pages from application mappings 115 //app-page=config.getCachedPage(pc, ":"+appName+":"+pathWithCFC); 116 //app-if(page!=null) return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 117 } 118 119 // SEARCH 120 // search from local 121 if(searchLocal && isRealPath) { 122 // check realpath 123 PageSource[] arr = ((PageContextImpl)pc).getRelativePageSources(pathWithCFC); 124 page=PageSourceImpl.loadPage(pc, arr,null); 125 if(page!=null){ 126 if(doCache)config.putCachedPageSource(localCacheName, page.getPageSource()); 127 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 128 } 129 } 130 131 // search with imports 132 Mapping[] cMappings = config.getComponentMappings(); 133 ApplicationContextPro ac=(ApplicationContextPro) pc.getApplicationContext(); 134 //Mapping[] lcMappings = ac.getComponentMappings(); 135 136 if(isRealPath){ 137 138 ImportDefintion impDef = config.getComponentDefaultImport(); 139 ImportDefintion[] impDefs=pp==null?new ImportDefintion[0]:pp.getImportDefintions(); 140 PageSource[] arr; 141 142 int i=-1; 143 do{ 144 if(impDef.isWildcard() || impDef.getName().equalsIgnoreCase(path)){ 145 146 // search from local first 147 if(searchLocal){ 148 arr = ((PageContextImpl)pc).getRelativePageSources(impDef.getPackageAsPath()+pathWithCFC); 149 page=PageSourceImpl.loadPage(pc, arr,null); 150 if(page!=null) { 151 if(doCache)config.putCachedPageSource("import:"+impDef.getPackageAsPath()+pathWithCFC, page.getPageSource()); 152 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 153 } 154 } 155 156 // search local component mappings 157 /*app-if(lcMappings!=null) { 158 Mapping m; 159 for(int y=0;y<lcMappings.length;y++){ 160 m=lcMappings[y]; 161 String key=appName+":"+impDef.getPackageAsPath()+pathWithCFC; 162 ps=m.getPageSource(impDef.getPackageAsPath()+pathWithCFC); 163 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 164 if(page!=null) { 165 if(doCache)config.putCachedPageSource("import:"+key, page.getPageSource()); 166 return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 167 } 168 } 169 }*/ 170 171 // search mappings and webroot 172 page=PageSourceImpl.loadPage(pc, ((PageContextImpl)pc).getPageSources("/"+impDef.getPackageAsPath()+pathWithCFC), null); 173 if(page!=null){ 174 String key=impDef.getPackageAsPath()+pathWithCFC; 175 if(doCache && !((MappingImpl)page.getPageSource().getMapping()).isAppMapping()) 176 config.putCachedPageSource("import:"+key, page.getPageSource()); 177 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 178 } 179 180 // search component mappings 181 Mapping m; 182 for(int y=0;y<cMappings.length;y++){ 183 m=cMappings[y]; 184 ps=m.getPageSource(impDef.getPackageAsPath()+pathWithCFC); 185 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 186 if(page!=null) { 187 if(doCache)config.putCachedPageSource("import:"+impDef.getPackageAsPath()+pathWithCFC, page.getPageSource()); 188 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 189 } 190 } 191 } 192 impDef=++i<impDefs.length?impDefs[i]:null; 193 } 194 while(impDef!=null); 195 196 } 197 198 String p; 199 if(isRealPath) p='/'+pathWithCFC; 200 else p=pathWithCFC; 201 202 203 204 // search local component mappings 205 /* app-if(lcMappings!=null) { 206 Mapping m; 207 for(int i=0;i<lcMappings.length;i++){ 208 m=lcMappings[i]; 209 ps=m.getPageSource(p); 210 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 211 String key=":"+appName+":"+pathWithCFC; 212 if(page!=null){ 213 if(doCache)config.putCachedPageSource(key, page.getPageSource()); 214 return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 215 } 216 } 217 }*/ 218 219 // search mappings and webroot 220 page=PageSourceImpl.loadPage(pc,((PageContextImpl)pc).getPageSources(p),null); 221 if(page!=null){ 222 String key=pathWithCFC; 223 if(doCache && !((MappingImpl)page.getPageSource().getMapping()).isAppMapping()) 224 config.putCachedPageSource(key, page.getPageSource()); 225 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 226 } 227 228 // search component mappings 229 Mapping m; 230 for(int i=0;i<cMappings.length;i++){ 231 m=cMappings[i]; 232 ps=m.getPageSource(p); 233 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 234 235 // recursive search 236 if(page==null && config.doComponentDeepSearch() && m.hasPhysical() && path.indexOf('/')==-1) { 237 String _path=getPagePath(pc, m.getPhysical(), null,pathWithCFC,DirectoryResourceFilter.FILTER); 238 if(_path!=null) { 239 ps=m.getPageSource(_path); 240 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 241 doCache=false;// do not cache this, it could be ambigous 242 } 243 } 244 245 if(page!=null){ 246 if(doCache)config.putCachedPageSource(pathWithCFC, page.getPageSource()); 247 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 248 } 249 } 250 251 252 // search relative to active cfc (this get not cached because the cache get ambigous if we do) 253 if(searchLocal && isRealPath) { 254 ComponentPro cfc = (ComponentPro) pc.getActiveComponent(); 255 if(cfc!=null) { 256 PageSource psCFC = cfc.getPageSource(); 257 ps=psCFC.getRealPage(pathWithCFC); 258 if(ps!=null) { 259 page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 260 261 if(page!=null){ 262 return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs); 263 } 264 } 265 } 266 } 267 268 // translate cfide. to org.railo.cfml 269 if(StringUtil.startsWithIgnoreCase(rawPath, "cfide.")) { 270 String rpm="org.railo.cfml."+rawPath.substring(6); 271 try{ 272 return load(pc,rpm, searchLocal, searchRoot, interfaceUDFs,returnPage); 273 } 274 catch(ExpressionException ee){ 275 throw new ExpressionException("invalid "+(interfaceUDFs==null?"component":"interface")+" definition, can't find "+rawPath+" or "+rpm); 276 } 277 } 278 else throw new ExpressionException("invalid "+(interfaceUDFs==null?"component":"interface")+" definition, can't find "+rawPath); 279 280 281 282 } 283 284 private static String getPagePath(PageContext pc, Resource res, String dir,String name, ResourceFilter filter) { 285 if(res.isFile()) { 286 if(res.getName().equalsIgnoreCase(name)) { 287 return dir+res.getName(); 288 } 289 } 290 else if(res.isDirectory()) { 291 Resource[] _dir = res.listResources(filter); 292 if(_dir!=null){ 293 if(dir==null) dir="/"; 294 else dir=dir+res.getName()+"/"; 295 String path; 296 for(int i=0;i<_dir.length;i++){ 297 path=getPagePath(pc, _dir[i],dir, name,DIR_OR_EXT); 298 if(path!=null) return path; 299 } 300 } 301 } 302 303 return null; 304 } 305 306 private static String trim(String str) { 307 if(StringUtil.startsWith(str, '.'))str=str.substring(1); 308 return str; 309 } 310 311 private static Page getPage(PageContext pc,String path, RefBoolean isRealPath, boolean searchLocal) throws PageException { 312 Page page=null; 313 isRealPath.setValue(!StringUtil.startsWith(path,'/')); 314 // search from local 315 PageSource[] arr; 316 317 if(searchLocal && isRealPath.toBooleanValue()){ 318 arr = ((PageContextImpl)pc).getRelativePageSources(path); 319 page=PageSourceImpl.loadPage(pc, arr, null); 320 //if(ps==null) return null; 321 //page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 322 } 323 // search from root 324 if(page==null) { 325 if(isRealPath.toBooleanValue()){ 326 isRealPath.setValue(false); 327 arr=((PageContextImpl)pc).getPageSources('/'+path); 328 } 329 else { 330 arr=((PageContextImpl)pc).getPageSources(path); 331 } 332 page=PageSourceImpl.loadPage(pc,arr,null); 333 //page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null); 334 } 335 return page; 336 } 337 338 339 // 340 341 public static ComponentImpl loadComponent(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, boolean silent) throws PageException { 342 /*if(page==null && ps instanceof PageSourceImpl) { 343 page=((PageSourceImpl)ps).getPage(); 344 }*/ 345 if(silent) { 346 // TODO is there a more direct way 347 BodyContent bc = pc.pushBody(); 348 try { 349 return loadComponent(pc,page,ps,callPath,isRealPath); 350 } 351 finally { 352 BodyContentUtil.clearAndPop(pc, bc); 353 } 354 } 355 return loadComponent(pc,page,ps,callPath,isRealPath); 356 } 357 358 359 private static Object load(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, Map interfaceUDFs) throws PageException { 360 if(interfaceUDFs==null) return loadComponent(pc,page, ps,callPath, isRealPath); 361 else return loadInterface(pc,page, ps, callPath, isRealPath, interfaceUDFs); 362 } 363 364 public static Page loadPage(PageContext pc,PageSource ps) throws PageException { 365 if(pc.getConfig().debug()) { 366 DebugEntry debugEntry=pc.getDebugger().getEntry(pc,ps); 367 pc.addPageSource(ps,true); 368 369 int currTime=pc.getExecutionTime(); 370 long exeTime=0; 371 long time=System.currentTimeMillis(); 372 try { 373 debugEntry.updateFileLoadTime((int)(System.currentTimeMillis()-time)); 374 exeTime=System.currentTimeMillis(); 375 return ((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 376 } 377 finally { 378 int diff= ((int)(System.currentTimeMillis()-exeTime)-(pc.getExecutionTime()-currTime)); 379 pc.setExecutionTime(pc.getExecutionTime()+(int)(System.currentTimeMillis()-time)); 380 debugEntry.updateExeTime(diff); 381 pc.removeLastPageSource(true); 382 } 383 } 384 // no debug 385 else { 386 pc.addPageSource(ps,true); 387 try { 388 return ((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 389 } 390 finally { 391 pc.removeLastPageSource(true); 392 } 393 } 394 } 395 396 public static ComponentImpl loadComponent(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath) throws PageException { 397 ComponentImpl rtn=null; 398 if(pc.getConfig().debug()) { 399 DebugEntry debugEntry=pc.getDebugger().getEntry(pc,ps); 400 pc.addPageSource(ps,true); 401 402 int currTime=pc.getExecutionTime(); 403 long exeTime=0; 404 long time=System.currentTimeMillis(); 405 try { 406 debugEntry.updateFileLoadTime((int)(System.currentTimeMillis()-time)); 407 exeTime=System.currentTimeMillis(); 408 if(page==null)page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 409 rtn=initComponent(pc,page,callPath,isRealPath); 410 411 412 } 413 finally { 414 int diff= ((int)(System.currentTimeMillis()-exeTime)-(pc.getExecutionTime()-currTime)); 415 pc.setExecutionTime(pc.getExecutionTime()+(int)(System.currentTimeMillis()-time)); 416 debugEntry.updateExeTime(diff); 417 pc.removeLastPageSource(true); 418 } 419 } 420 // no debug 421 else { 422 pc.addPageSource(ps,true); 423 try { 424 if(page==null)page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 425 rtn=initComponent(pc,page,callPath,isRealPath); 426 } 427 finally { 428 pc.removeLastPageSource(true); 429 } 430 } 431 432 return rtn; 433 } 434 435 public static InterfaceImpl loadInterface(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, Map interfaceUDFs) throws PageException { 436 InterfaceImpl rtn=null; 437 if(pc.getConfig().debug()) { 438 DebugEntry debugEntry=pc.getDebugger().getEntry(pc,ps); 439 pc.addPageSource(ps,true); 440 441 int currTime=pc.getExecutionTime(); 442 long exeTime=0; 443 long time=System.currentTimeMillis(); 444 try { 445 debugEntry.updateFileLoadTime((int)(System.currentTimeMillis()-time)); 446 exeTime=System.currentTimeMillis(); 447 if(page==null)page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 448 rtn=initInterface(pc,page,callPath,isRealPath,interfaceUDFs); 449 } 450 finally { 451 int diff= ((int)(System.currentTimeMillis()-exeTime)-(pc.getExecutionTime()-currTime)); 452 pc.setExecutionTime(pc.getExecutionTime()+(int)(System.currentTimeMillis()-time)); 453 debugEntry.updateExeTime(diff); 454 pc.removeLastPageSource(true); 455 } 456 } 457 // no debug 458 else { 459 pc.addPageSource(ps,true); 460 try { 461 if(page==null)page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig()); 462 rtn=initInterface(pc,page,callPath,isRealPath,interfaceUDFs); 463 } 464 finally { 465 pc.removeLastPageSource(true); 466 } 467 } 468 return rtn; 469 } 470 471 472 473 /* * 474 * load a component 475 * @param rawPath 476 * @return loaded component 477 * @throws PageException 478 * / 479 public static InterfaceImpl loadInterface(PageContext pc,String rawPath,boolean allowRemovingExt, Map interfaceUDFs) throws PageException { 480 // MUSTMUST sync code with extends 481 482 String fullName=rawPath; 483 boolean hasRemovedExt=false; 484 485 fullName=fullName.trim().replace('\\','/').replace('.','/'); 486 String path=fullName.concat(".cfc"); 487 488 489 boolean isRealPath=!StringUtil.startsWith(fullName,'/'); 490 491 PageSource res=pc.getRelativePageSource(path); 492 Page page=null; 493 //try { 494 page=((PageSourceImpl)res).loadPage(pc,pc.getConfig(),null); 495 if(page==null && isRealPath) { 496 isRealPath=false; 497 PageSource resOld = res; 498 res=pc.getPageSource('/'+path); 499 page=((PageSourceImpl)res).loadPage(pc,pc.getConfig(),null); 500 if(page==null) { 501 if(hasRemovedExt)return loadInterface(pc,rawPath, false,interfaceUDFs); 502 String detail="search for "+res.getDisplayPath(); 503 if(resOld!=null)detail+=" and "+resOld.getDisplayPath(); 504 505 if(StringUtil.startsWithIgnoreCase(rawPath, "cfide.")) { 506 String rpm="org.railo.cfml."+rawPath.substring(6); 507 try{ 508 return loadInterface(pc,rpm,allowRemovingExt, interfaceUDFs); 509 } 510 catch(ExpressionException ee){ 511 throw new ExpressionException("invalid interface definition, can't find "+rawPath+" or "+rpm,detail); 512 } 513 } 514 else throw new ExpressionException("invalid interface definition, can't find "+rawPath,detail); 515 516 517 } 518 } 519 return loadInterface(pc,page,res,fullName.replace('/', '.'),isRealPath,interfaceUDFs); 520 }*/ 521 522 523 524 525 526 private static InterfaceImpl initInterface(PageContext pc,Page page,String callPath,boolean isRealPath, Map interfaceUDFs) throws PageException { 527 if(!(page instanceof InterfacePage)) 528 throw new ApplicationException("invalid interface definition ["+callPath+"]"); 529 InterfacePage ip=(InterfacePage)page; 530 InterfaceImpl i = ip.newInstance(callPath,isRealPath,interfaceUDFs); 531 return i; 532 } 533 534 private static ComponentImpl initComponent(PageContext pc,Page page,String callPath,boolean isRealPath) throws PageException { 535 if(!(page instanceof ComponentPage)){ 536 if(page instanceof InterfacePage) 537 throw new ApplicationException("can not instantiate interface ["+callPath+"] as a component"); 538 throw new ApplicationException("invalid component definition ["+callPath+"]"); 539 } 540 541 ComponentPage cp = (ComponentPage)page; 542 543 ComponentImpl c = cp.newInstance(pc,callPath,isRealPath); 544 c.setInitalized(true); 545 return c; 546 547 } 548 }