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