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