001 package railo.runtime; 002 003 import java.io.FileNotFoundException; 004 import java.io.IOException; 005 import java.io.InputStream; 006 import java.lang.reflect.Constructor; 007 import java.lang.reflect.InvocationTargetException; 008 009 import railo.commons.io.IOUtil; 010 import railo.commons.io.res.Resource; 011 import railo.commons.io.res.util.ResourceUtil; 012 import railo.commons.lang.SizeOf; 013 import railo.commons.lang.StringUtil; 014 import railo.commons.lang.types.RefBoolean; 015 import railo.commons.lang.types.RefBooleanImpl; 016 import railo.runtime.config.ConfigWeb; 017 import railo.runtime.config.ConfigWebImpl; 018 import railo.runtime.engine.ThreadLocalPageContext; 019 import railo.runtime.engine.ThreadLocalPageSource; 020 import railo.runtime.exp.MissingIncludeException; 021 import railo.runtime.exp.PageException; 022 import railo.runtime.exp.TemplateException; 023 import railo.runtime.op.Caster; 024 import railo.runtime.type.List; 025 import railo.runtime.type.Sizeable; 026 import railo.runtime.type.util.ArrayUtil; 027 028 /** 029 * represent a cfml file on the runtime system 030 */ 031 public final class PageSourceImpl implements SourceFile, PageSource, Sizeable { 032 033 private static final long serialVersionUID = -7661676586215092539L; 034 //public static final byte LOAD_NONE=1; 035 public static final byte LOAD_ARCHIVE=2; 036 public static final byte LOAD_PHYSICAL=3; 037 038 //private byte load=LOAD_NONE; 039 040 private final MappingImpl mapping; 041 private final String realPath; 042 043 private boolean isOutSide; 044 045 private String className; 046 private String packageName; 047 private String javaName; 048 049 private Resource physcalSource; 050 private Resource archiveSource; 051 private String fileName; 052 private String compName; 053 private PagePlus page; 054 private long lastAccess; 055 private int accessCount=0; 056 //private boolean recompileAlways; 057 //private boolean recompileAfterStartUp; 058 059 060 061 private PageSourceImpl() { 062 mapping=null; 063 realPath=null; 064 } 065 066 067 /** 068 * constructor of the class 069 * @param mapping 070 * @param realPath 071 */ 072 PageSourceImpl(MappingImpl mapping,String realPath) { 073 this.mapping=mapping; 074 //recompileAlways=mapping.getConfig().getCompileType()==Config.RECOMPILE_ALWAYS; 075 //recompileAfterStartUp=mapping.getConfig().getCompileType()==Config.RECOMPILE_AFTER_STARTUP || recompileAlways; 076 realPath=realPath.replace('\\','/'); 077 if(realPath.indexOf('/')!=0) { 078 if(realPath.startsWith("../")) { 079 isOutSide=true; 080 } 081 else if(realPath.startsWith("./")) { 082 realPath=realPath.substring(1); 083 } 084 else { 085 realPath="/"+realPath; 086 } 087 } 088 this.realPath=realPath; 089 090 } 091 092 /** 093 * private constructor of the class 094 * @param mapping 095 * @param realPath 096 * @param isOutSide 097 */ 098 PageSourceImpl(MappingImpl mapping, String realPath, boolean isOutSide) { 099 //recompileAlways=mapping.getConfig().getCompileType()==Config.RECOMPILE_ALWAYS; 100 //recompileAfterStartUp=mapping.getConfig().getCompileType()==Config.RECOMPILE_AFTER_STARTUP || recompileAlways; 101 this.mapping=mapping; 102 this.isOutSide=isOutSide; 103 this.realPath=realPath; 104 105 } 106 107 108 /** 109 * @see railo.runtime.PageSource#loadPage(railo.runtime.PageContext) 110 */ 111 public Page loadPage(ConfigWeb config) throws PageException { 112 return loadPage(null,config); 113 } 114 115 116 /** 117 * return page when already loaded, otherwise null 118 * @param pc 119 * @param config 120 * @return 121 * @throws PageException 122 */ 123 public Page getPage() { 124 return page; 125 } 126 127 // FUTURE add to interface without config 128 public Page loadPage(PageContext pc,ConfigWeb config) throws PageException { 129 PagePlus page=this.page; 130 if(mapping.isPhysicalFirst()) { 131 page=loadPhysical(pc,page,config); 132 if(page==null) page=loadArchive(page); 133 if(page!=null) return page; 134 } 135 else { 136 page=loadArchive(page); 137 if(page==null)page=loadPhysical(pc,page,config); 138 if(page!=null) return page; 139 } 140 throw new MissingIncludeException(this); 141 142 } 143 144 145 /** 146 * @see railo.runtime.PageSource#loadPage(railo.runtime.PageContext, railo.runtime.Page) 147 */ 148 public Page loadPage(ConfigWeb config, Page defaultValue) throws PageException { 149 return loadPage(null,config, defaultValue); 150 } 151 152 public Page loadPage(PageContext pc,ConfigWeb config, Page defaultValue) throws PageException { 153 PagePlus page=this.page; 154 if(mapping.isPhysicalFirst()) { 155 page=loadPhysical(pc,page,config); 156 if(page==null) page=loadArchive(page); 157 if(page!=null) return page; 158 } 159 else { 160 page=loadArchive(page); 161 if(page==null)page=loadPhysical(pc,page,config); 162 if(page!=null) return page; 163 } 164 return defaultValue; 165 } 166 167 private PagePlus loadArchive(PagePlus page) { 168 if(!mapping.hasArchive()) return null; 169 if(page!=null) return page; 170 171 try { 172 synchronized(this) { 173 Class clazz=mapping.getClassLoaderForArchive().loadClass(getClazz()); 174 this.page=page=newInstance(clazz); 175 page.setPageSource(this); 176 //page.setTimeCreated(System.currentTimeMillis()); 177 page.setLoadType(LOAD_ARCHIVE); 178 ////load=LOAD_ARCHIVE; 179 return page; 180 } 181 } 182 catch (Exception e) { 183 return null; 184 } 185 } 186 187 188 private PagePlus loadPhysical(PageContext pc,PagePlus page, ConfigWeb config) throws PageException { 189 if(!mapping.hasPhysical()) return null; 190 191 // FUTURE change interface loadPage to PageContext 192 pc=ThreadLocalPageContext.get(pc); 193 PageContextImpl pci=(PageContextImpl) pc; 194 //if(pc.isPageAlreadyUsed(page)) return page; 195 196 if((mapping.isTrusted() || 197 pc!=null && pci.isTrusted(page)) 198 && isLoad(LOAD_PHYSICAL)) return page; 199 //&& isLoad(LOAD_PHYSICAL) && !recompileAlways) return page; 200 201 Resource srcFile = getPhyscalFile(); 202 203 long srcLastModified = srcFile.lastModified(); 204 205 if(srcLastModified==0L) return null; 206 207 // Page exists 208 if(page!=null) { 209 //if(page!=null && !recompileAlways) { 210 // java file is newer !mapping.isTrusted() && 211 if(srcLastModified!=page.getSourceLastModified()) { 212 this.page=page=compile(config,mapping.getClassRootDirectory(),Boolean.TRUE); 213 page.setPageSource(this); 214 page.setLoadType(LOAD_PHYSICAL); 215 } 216 217 } 218 // page doesn't exist 219 else { 220 ///synchronized(this) { 221 Resource classRootDir=mapping.getClassRootDirectory(); 222 Resource classFile=classRootDir.getRealResource(getJavaName()+".class"); 223 boolean isNew=false; 224 // new class 225 if(!classFile.exists()) { 226 //if(!classFile.exists() || recompileAfterStartUp) { 227 this.page=page= compile(config,classRootDir,Boolean.FALSE); 228 isNew=true; 229 } 230 // load page 231 else { 232 try { 233 this.page=page=newInstance(mapping.touchPCLCollection().getClass(this)); 234 } catch (Throwable t) {t.printStackTrace(); 235 this.page=page=null; 236 } 237 if(page==null) this.page=page=compile(config,classRootDir,Boolean.TRUE); 238 239 } 240 241 // check if there is a newwer version 242 if(!isNew && srcLastModified!=page.getSourceLastModified()) { 243 isNew=true; 244 this.page=page=compile(config,classRootDir,null); 245 } 246 247 // check version 248 if(!isNew && page.getVersion()!=Info.getFullVersionInfo()) { 249 isNew=true; 250 this.page=page=compile(config,classRootDir,null); 251 } 252 253 page.setPageSource(this); 254 page.setLoadType(LOAD_PHYSICAL); 255 256 } 257 if(pc!=null)pci.setPageUsed(page); 258 return page; 259 } 260 261 private boolean isLoad(byte load) { 262 return page!=null && load==page.getLoadType(); 263 } 264 265 266 private synchronized PagePlus compile(ConfigWeb config,Resource classRootDir, Boolean resetCL) throws PageException { 267 try { 268 return _compile(config, classRootDir, resetCL); 269 } 270 catch(ClassFormatError e) { 271 String msg=StringUtil.emptyIfNull(e.getMessage()); 272 if(StringUtil.indexOfIgnoreCase(msg, "Invalid method Code length")!=-1) { 273 throw new TemplateException("There is too much code inside the template ["+getDisplayPath()+"], Railo was not able to break it into pieces, move parts of your code to an include or a external component/function",msg); 274 } 275 throw Caster.toPageException(e); 276 } 277 catch(Throwable t) { 278 throw Caster.toPageException(t); 279 } 280 } 281 282 private synchronized PagePlus _compile(ConfigWeb config,Resource classRootDir, Boolean resetCL) throws TemplateException, IOException, ClassNotFoundException, SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { 283 ConfigWebImpl cwi=(ConfigWebImpl) config; 284 byte[] barr = cwi.getCompiler(). 285 compile(cwi,this,cwi.getTLDs(),cwi.getFLDs(),classRootDir,getJavaName()); 286 Class<?> clazz = mapping.touchPCLCollection().loadClass(getClazz(), barr,isComponent()); 287 return newInstance(clazz); 288 } 289 290 private PagePlus newInstance(Class clazz) throws SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { 291 try{ 292 Constructor c = clazz.getConstructor(new Class[]{PageSource.class}); 293 return (PagePlus) c.newInstance(new Object[]{this}); 294 } 295 // this only happens with old code from ra files 296 catch(NoSuchMethodException e){ 297 ThreadLocalPageSource.register(this); 298 try{ 299 return (PagePlus) clazz.newInstance(); 300 } 301 finally { 302 ThreadLocalPageSource.release(); 303 } 304 305 306 } 307 } 308 309 310 /** 311 * return source path as String 312 * @return source path as String 313 */ 314 public String getDisplayPath() { 315 if(!mapping.hasArchive()) { 316 return StringUtil.toString(getPhyscalFile(), null); 317 } 318 else if(isLoad(LOAD_PHYSICAL)) { 319 return StringUtil.toString(getPhyscalFile(), null); 320 } 321 else if(isLoad(LOAD_ARCHIVE)) { 322 return StringUtil.toString(getArchiveSourcePath(), null); 323 } 324 else { 325 boolean pse = physcalExists(); 326 boolean ase = archiveExists(); 327 328 if(mapping.isPhysicalFirst()) { 329 if(pse)return getPhyscalFile().toString(); 330 else if(ase)return getArchiveSourcePath(); 331 return getPhyscalFile().toString(); 332 } 333 if(ase)return getArchiveSourcePath(); 334 else if(pse)return getPhyscalFile().toString(); 335 return getArchiveSourcePath(); 336 } 337 } 338 339 public boolean isComponent() { 340 return ResourceUtil.getExtension(getRealpath(), "").equalsIgnoreCase(mapping.getConfig().getCFCExtension()); 341 } 342 343 /** 344 * return file object, based on physical path and realpath 345 * @return file Object 346 */ 347 private String getArchiveSourcePath() { 348 return "ra://"+mapping.getArchive().getAbsolutePath()+"!"+realPath; 349 } 350 351 /** 352 * return file object, based on physical path and realpath 353 * @return file Object 354 */ 355 public Resource getPhyscalFile() { 356 if(physcalSource==null) { 357 if(!mapping.hasPhysical()) { 358 return null; 359 } 360 physcalSource=ResourceUtil.toExactResource(mapping.getPhysical().getRealResource(realPath)); 361 } 362 return physcalSource; 363 } 364 365 public Resource getArchiveFile() { 366 if(archiveSource==null) { 367 if(!mapping.hasArchive()) return null; 368 String path="zip://"+mapping.getArchive().getAbsolutePath()+"!"+realPath; 369 archiveSource = ThreadLocalPageContext.getConfig().getResource(path); 370 } 371 return archiveSource; 372 } 373 374 375 /** 376 * merge to realpath to one 377 * @param mapping 378 * @param parentRealPath 379 * @param newRealPath 380 * @param isOutSide 381 * @return merged realpath 382 */ 383 private static String mergeRealPathes(Mapping mapping,String parentRealPath, String newRealPath, RefBoolean isOutSide) { 384 parentRealPath=pathRemoveLast(parentRealPath,isOutSide); 385 while(newRealPath.startsWith("../")) { 386 parentRealPath=pathRemoveLast(parentRealPath,isOutSide); 387 newRealPath=newRealPath.substring(3); 388 } 389 390 // check if come back 391 String path=parentRealPath.concat("/").concat(newRealPath); 392 393 if(path.startsWith("../")) { 394 int count=0; 395 do { 396 count++; 397 path=path.substring(3); 398 }while(path.startsWith("../")); 399 400 String strRoot=mapping.getPhysical().getAbsolutePath().replace('\\','/'); 401 if(!StringUtil.endsWith(strRoot,'/')) { 402 strRoot+='/'; 403 } 404 int rootLen=strRoot.length(); 405 String[] arr=List.toStringArray(List.listToArray(path,'/'),"");//path.split("/"); 406 int tmpLen; 407 for(int i=count;i>0;i--) { 408 if(arr.length>i) { 409 String tmp='/'+list(arr,0,i); 410 tmpLen=rootLen-tmp.length(); 411 if(strRoot.lastIndexOf(tmp)==tmpLen && tmpLen>=0) { 412 StringBuffer rtn=new StringBuffer(); 413 for(int y=0;i<count-i;y++) rtn.append("../"); 414 isOutSide.setValue(rtn.length()!=0); 415 return (rtn.length()==0?"/":rtn.toString())+list(arr,i,arr.length); 416 } 417 } 418 } 419 } 420 return parentRealPath.concat("/").concat(newRealPath); 421 } 422 423 /** 424 * convert a String array to a string list, but only part of it 425 * @param arr String Array 426 * @param from start from here 427 * @param len how many element 428 * @return String list 429 */ 430 private static String list(String[] arr,int from, int len) { 431 StringBuffer sb=new StringBuffer(); 432 for(int i=from;i<len;i++) { 433 sb.append(arr[i]); 434 if(i+1!=arr.length)sb.append('/'); 435 } 436 return sb.toString(); 437 } 438 439 440 441 /** 442 * remove the last elemtn of a path 443 * @param path path to remove last element from it 444 * @param isOutSide 445 * @return path with removed element 446 */ 447 private static String pathRemoveLast(String path, RefBoolean isOutSide) { 448 if(path.length()==0) { 449 isOutSide.setValue(true); 450 return ".."; 451 } 452 else if(path.endsWith("..")){ 453 isOutSide.setValue(true); 454 return path.concat("/..");//path+"/.."; 455 } 456 return path.substring(0,path.lastIndexOf('/')); 457 } 458 459 /** 460 * @see railo.runtime.PageSource#getRealpath() 461 */ 462 public String getRealpath() { 463 return realPath; 464 } 465 /** 466 * @see railo.runtime.PageSource#getFullRealpath() 467 */ 468 public String getFullRealpath() { 469 if(mapping.getVirtual().length()==1 || mapping.ignoreVirtual()) 470 return realPath; 471 return mapping.getVirtual()+realPath; 472 } 473 474 /** 475 * @return returns a variable string based on realpath and return it 476 */ 477 public String getRealPathAsVariableString() { 478 return StringUtil.toIdentityVariableName(realPath); 479 } 480 481 /** 482 * @see railo.runtime.PageSource#getClazz() 483 */ 484 public String getClazz() { 485 if(className==null) createClassAndPackage(); 486 if(packageName.length()>0) return packageName+'.'+className; 487 return className; 488 } 489 490 /** 491 * @return returns the a classname matching to filename (Example: test_cfm) 492 */ 493 public String getClassName() { 494 if(className==null) createClassAndPackage(); 495 return className; 496 } 497 498 /** 499 * @see railo.runtime.PageSource#getFileName() 500 */ 501 public String getFileName() { 502 if(fileName==null) createClassAndPackage(); 503 return fileName; 504 } 505 506 /** 507 * @see railo.runtime.PageSource#getJavaName() 508 */ 509 public String getJavaName() { 510 if(javaName==null) createClassAndPackage(); 511 return javaName; 512 } 513 514 /** 515 * @return returns the a package matching to file (Example: railo.web) 516 */ 517 public String getPackageName() { 518 if(packageName==null) createClassAndPackage(); 519 return packageName; 520 } 521 /** 522 * @see railo.runtime.PageSource#getComponentName() 523 */ 524 public String getComponentName() { 525 if(compName==null) createComponentName(); 526 return compName; 527 } 528 529 530 private synchronized void createClassAndPackage() { 531 String str=realPath; 532 StringBuffer packageName=new StringBuffer(); 533 StringBuffer javaName=new StringBuffer(); 534 535 String[] arr=List.toStringArrayEL(List.listToArrayRemoveEmpty(str,'/')); 536 537 String varName; 538 for(int i=0;i<arr.length;i++) { 539 if(i==(arr.length-1)) { 540 int index=arr[i].lastIndexOf('.'); 541 if(index!=-1){ 542 String ext=arr[i].substring(index+1); 543 varName=StringUtil.toVariableName(arr[i].substring(0,index)+"_"+ext); 544 } 545 else varName=StringUtil.toVariableName(arr[i]); 546 varName=varName+"$cf"; 547 className=varName.toLowerCase(); 548 fileName=arr[i]; 549 } 550 else { 551 varName=StringUtil.toVariableName(arr[i]); 552 if(i!=0) { 553 packageName.append('.'); 554 } 555 packageName.append(varName); 556 } 557 javaName.append('/'); 558 javaName.append(varName); 559 } 560 561 this.packageName=packageName.toString().toLowerCase(); 562 this.javaName=javaName.toString().toLowerCase(); 563 564 565 566 } 567 568 569 570 private synchronized void createComponentName() { 571 Resource res = this.getPhyscalFile(); 572 String str=null; 573 if(res!=null) { 574 575 str=res.getAbsolutePath(); 576 str=str.substring(str.length()-realPath.length()); 577 if(!str.equalsIgnoreCase(realPath)) { 578 str=realPath; 579 } 580 } 581 else str=realPath; 582 583 StringBuffer compName=new StringBuffer(); 584 String[] arr; 585 586 // virtual part 587 if(!mapping.ignoreVirtual()) { 588 arr=List.toStringArrayEL(List.listToArrayRemoveEmpty(mapping.getVirtual(),"\\/")); 589 for(int i=0;i<arr.length;i++) { 590 if(compName.length()>0) compName.append('.'); 591 compName.append(arr[i]); 592 } 593 } 594 595 // physical part 596 arr=List.toStringArrayEL(List.listToArrayRemoveEmpty(str,'/')); 597 for(int i=0;i<arr.length;i++) { 598 if(compName.length()>0) compName.append('.'); 599 if(i==(arr.length-1)) { 600 compName.append(arr[i].substring(0,arr[i].length()-4)); 601 } 602 else compName.append(arr[i]); 603 } 604 this.compName=compName.toString(); 605 } 606 607 /** 608 * @see railo.runtime.PageSource#getMapping() 609 */ 610 public Mapping getMapping() { 611 return mapping; 612 } 613 614 /** 615 * @see railo.runtime.PageSource#exists() 616 */ 617 public synchronized boolean exists() { 618 if(mapping.isPhysicalFirst()) 619 return physcalExists() || archiveExists(); 620 return archiveExists() || physcalExists(); 621 } 622 623 /** 624 * @see railo.runtime.PageSource#physcalExists() 625 */ 626 public boolean physcalExists() { 627 return ResourceUtil.exists(getPhyscalFile()); 628 } 629 630 private boolean archiveExists() { 631 if(!mapping.hasArchive())return false; 632 try { 633 String clazz = getClazz(); 634 if(clazz==null) return getArchiveFile().exists(); 635 mapping.getClassLoaderForArchive().loadClass(clazz); 636 return true; 637 } 638 catch(ClassNotFoundException cnfe){ 639 return false; 640 } 641 catch (Exception e) { 642 return getArchiveFile().exists(); 643 } 644 } 645 646 /** 647 * return the inputstream of the source file 648 * @return return the inputstream for the source from ohysical or archive 649 * @throws FileNotFoundException 650 */ 651 private InputStream getSourceAsInputStream() throws IOException { 652 if(!mapping.hasArchive()) return IOUtil.toBufferedInputStream(getPhyscalFile().getInputStream()); 653 else if(isLoad(LOAD_PHYSICAL)) return IOUtil.toBufferedInputStream(getPhyscalFile().getInputStream()); 654 else if(isLoad(LOAD_ARCHIVE)) { 655 StringBuffer name=new StringBuffer(getPackageName().replace('.','/')); 656 if(name.length()>0)name.append("/"); 657 name.append(getFileName()); 658 659 return mapping.getClassLoaderForArchive().getResourceAsStream(name.toString()); 660 } 661 else { 662 return null; 663 } 664 } 665 /** 666 * @see railo.runtime.PageSource#getSource() 667 */ 668 public String[] getSource() throws IOException { 669 //if(source!=null) return source; 670 InputStream is = getSourceAsInputStream(); 671 if(is==null) return null; 672 try { 673 return IOUtil.toStringArray(IOUtil.getReader(is,getMapping().getConfig().getTemplateCharset())); 674 } 675 finally { 676 IOUtil.closeEL(is); 677 } 678 } 679 680 /** 681 * @see java.lang.Object#equals(java.lang.Object) 682 */ 683 public boolean equals(Object obj) { 684 if(this==obj) return true; 685 if(!(obj instanceof PageSource)) return false; 686 return getClassName().equals(((PageSource)obj).getClassName()); 687 //return equals((PageSource)obj); 688 } 689 690 /** 691 * is given object equal to this 692 * @param other 693 * @return is same 694 */ 695 public boolean equals(PageSource other) { 696 if(this==other) return true; 697 return getClassName().equals(other.getClassName()); 698 } 699 700 /** 701 * @see railo.runtime.PageSource#getRealPage(java.lang.String) 702 */ 703 public PageSource getRealPage(String realPath) { 704 if(realPath.equals(".") || realPath.equals(".."))realPath+='/'; 705 else realPath=realPath.replace('\\','/'); 706 RefBoolean _isOutSide=new RefBooleanImpl(isOutSide); 707 708 709 if(realPath.indexOf('/')==0) { 710 _isOutSide.setValue(false); 711 } 712 else if(realPath.startsWith("./")) { 713 realPath=mergeRealPathes(mapping,this.realPath, realPath.substring(2),_isOutSide); 714 } 715 else { 716 realPath=mergeRealPathes(mapping,this.realPath, realPath,_isOutSide); 717 } 718 return mapping.getPageSource(realPath,_isOutSide.toBooleanValue()); 719 } 720 721 /** 722 * @see railo.runtime.PageSource#setLastAccessTime(long) 723 */ 724 public final void setLastAccessTime(long lastAccess) { 725 this.lastAccess=lastAccess; 726 } 727 728 /** 729 * @see railo.runtime.PageSource#getLastAccessTime() 730 */ 731 public final long getLastAccessTime() { 732 return lastAccess; 733 } 734 735 /** 736 * @see railo.runtime.PageSource#setLastAccessTime() 737 */ 738 public synchronized final void setLastAccessTime() { 739 accessCount++; 740 this.lastAccess=System.currentTimeMillis(); 741 } 742 743 /** 744 * @see railo.runtime.PageSource#getAccessCount() 745 */ 746 public final int getAccessCount() { 747 return accessCount; 748 } 749 750 /** 751 * @see railo.runtime.SourceFile#getFile() 752 */ 753 public Resource getFile() { 754 Resource res = getPhyscalFile(); 755 if(res!=null) return res; 756 return getArchiveFile(); 757 } 758 759 760 public void clear() { 761 if(page!=null){ 762 page=null; 763 } 764 } 765 766 /** 767 * clear page, but only when page use the same clasloader as provided 768 * @param cl 769 */ 770 public void clear(ClassLoader cl) { 771 if(page!=null && page.getClass().getClassLoader().equals(cl)){ 772 page=null; 773 } 774 } 775 776 /** 777 * @see railo.runtime.SourceFile#getFullClassName() 778 */ 779 public String getFullClassName() { 780 String s=_getFullClassName(); 781 return s; 782 } 783 784 public String _getFullClassName() { 785 String p=getPackageName(); 786 if(p.length()==0) return getClassName(); 787 return p.concat(".").concat(getClassName()); 788 } 789 790 public boolean isLoad() { 791 return page!=null;////load!=LOAD_NONE; 792 } 793 794 /** 795 * @see java.lang.Object#toString() 796 */ 797 public String toString() { 798 return getDisplayPath(); 799 } 800 801 /** 802 * @see railo.runtime.type.Sizeable#sizeOf() 803 */ 804 public long sizeOf() { 805 return SizeOf.size(page,0)+ 806 SizeOf.size(className)+ 807 SizeOf.size(packageName)+ 808 SizeOf.size(javaName)+ 809 SizeOf.size(fileName)+ 810 SizeOf.size(compName)+ 811 SizeOf.size(lastAccess)+ 812 SizeOf.size(accessCount); 813 } 814 815 public static PageSource best(PageSource[] arr) { 816 if(ArrayUtil.isEmpty(arr)) return null; 817 if(arr.length==1)return arr[0]; 818 for(int i=0;i<arr.length;i++) { 819 if(pageExist(arr[i])) return arr[i]; 820 } 821 return arr[0]; 822 } 823 824 public static boolean pageExist(PageSource ps) { 825 return (ps.getMapping().isTrusted() && ((PageSourceImpl)ps).isLoad()) || ps.exists(); 826 } 827 828 public static Page loadPage(PageContext pc,PageSource[] arr,Page defaultValue) throws PageException { 829 if(ArrayUtil.isEmpty(arr)) return null; 830 Page p; 831 for(int i=0;i<arr.length;i++) { 832 p=((PageSourceImpl)arr[i]).loadPage(pc,pc.getConfig(), null);//FUTURE remove cast 833 if(p!=null) return p; 834 } 835 return defaultValue; 836 } 837 838 public static Page loadPage(PageContext pc,PageSource[] arr) throws PageException { 839 if(ArrayUtil.isEmpty(arr)) return null; 840 841 Page p; 842 for(int i=0;i<arr.length;i++) { 843 p=((PageSourceImpl)arr[i]).loadPage(pc,pc.getConfig(), null);//FUTURE remove cast 844 if(p!=null) return p; 845 } 846 throw new MissingIncludeException(arr[0]); 847 } 848 849 850 851 }