/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import lucee.aprint;
import lucee.commons.io.IOUtil;
import lucee.commons.io.res.Resource;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.commons.lang.ClassUtil;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.types.RefBoolean;
import lucee.commons.lang.types.RefBooleanImpl;
import lucee.commons.lang.types.RefIntegerSync;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.compiler.CFMLCompilerImpl.Result;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.config.ConfigWeb;
import lucee.runtime.config.ConfigWebImpl;
import lucee.runtime.config.ConfigWebUtil;
import lucee.runtime.config.Constants;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.runtime.exp.ExpressionException;
import lucee.runtime.exp.MissingIncludeException;
import lucee.runtime.exp.PageException;
import lucee.runtime.exp.PageRuntimeException;
import lucee.runtime.exp.TemplateException;
import lucee.runtime.functions.system.GetDirectoryFromPath;
import lucee.runtime.op.Caster;
import lucee.runtime.type.util.ArrayUtil;
import lucee.runtime.type.util.ListUtil;
/**
* represent a cfml file on the runtime system
*/
public final class PageSourceImpl implements PageSource {
private static final long serialVersionUID = -7661676586215092539L;
//public static final byte LOAD_NONE=1;
public static final byte LOAD_ARCHIVE=2;
public static final byte LOAD_PHYSICAL=3;
//private byte load=LOAD_NONE;
private final MappingImpl mapping;
private boolean isOutSide;
private String relPath;
private String packageName;
private String javaName;
private String className;
private String fileName;
private Resource physcalSource;
private Resource archiveSource;
private String compName;
private Page page;
private long lastAccess;
private RefIntegerSync accessCount=new RefIntegerSync();
private boolean flush=false;
private PageSourceImpl() {
mapping=null;
relPath=null;
}
/**
* constructor of the class
* @param mapping
* @param realPath
*/
PageSourceImpl(MappingImpl mapping,String realPath) {
this.mapping=mapping;
realPath=realPath.replace('\\','/');
if(realPath.indexOf("//")!=-1) {
realPath=StringUtil.replace(realPath, "//", "/",false);
}
if(realPath.indexOf('/')!=0) {
if(realPath.startsWith("../")) {
isOutSide=true;
}
else if(realPath.startsWith("./")) {
realPath=realPath.substring(1);
}
else {
realPath="/"+realPath;
}
}
this.relPath=realPath;
}
/**
* private constructor of the class
* @param mapping
* @param realPath
* @param isOutSide
*/
PageSourceImpl(MappingImpl mapping, String realPath, boolean isOutSide) {
//recompileAlways=mapping.getConfig().getCompileType()==Config.RECOMPILE_ALWAYS;
//recompileAfterStartUp=mapping.getConfig().getCompileType()==Config.RECOMPILE_AFTER_STARTUP || recompileAlways;
this.mapping=mapping;
this.isOutSide=isOutSide;
if(realPath.indexOf("//")!=-1) {
realPath=StringUtil.replace(realPath, "//", "/",false);
}this.relPath=realPath;
}
/**
* return page when already loaded, otherwise null
* @param pc
* @param config
* @return
* @throws PageException
*/
public Page getPage() {
return page;
}
public PageSource getParent(){
if(relPath.equals("/")) return null;
if(StringUtil.endsWith(relPath, '/'))
return new PageSourceImpl(mapping, GetDirectoryFromPath.invoke(relPath.substring(0, relPath.length()-1)));
return new PageSourceImpl(mapping, GetDirectoryFromPath.invoke(relPath));
}
@Override
public Page loadPage(PageContext pc, boolean forceReload) throws PageException {
if(forceReload) page=null;
Page page=this.page;
if(mapping.isPhysicalFirst()) {
page=loadPhysical(pc,page);
if(page==null) page=loadArchive(page);
if(page!=null) return page;
}
else {
page=loadArchive(page);
if(page==null)page=loadPhysical(pc,page);
if(page!=null) return page;
}
throw new MissingIncludeException(this);
}
@Override
public Page loadPageThrowTemplateException(PageContext pc, boolean forceReload, Page defaultValue) throws TemplateException {
if(forceReload) page=null;
Page page=this.page;
if(mapping.isPhysicalFirst()) {
page=loadPhysical(pc,page);
if(page==null) page=loadArchive(page);
if(page!=null) return page;
}
else {
page=loadArchive(page);
if(page==null)page=loadPhysical(pc,page);
if(page!=null) return page;
}
return defaultValue;
}
@Override
public Page loadPage(PageContext pc, boolean forceReload, Page defaultValue) {
if(forceReload) page=null;
Page page=this.page;
if(mapping.isPhysicalFirst()) {
try {
page=loadPhysical(pc,page);
}
catch (TemplateException e) {
page=null;
}
if(page==null) page=loadArchive(page);
if(page!=null) return page;
}
else {
page=loadArchive(page);
if(page==null){
try {
page=loadPhysical(pc,page);
}
catch (TemplateException e) {}
}
if(page!=null) return page;
}
return defaultValue;
}
private Page loadArchive(Page page) {
if(!mapping.hasArchive()) return null;
if(page!=null && page.getLoadType()==LOAD_ARCHIVE) return page;
try {
Class clazz=mapping.getArchiveClass(getClassName());
page=newInstance(clazz);
synchronized(this) {
page.setPageSource(this);
page.setLoadType(LOAD_ARCHIVE);
this.page=page;
}
return page;
}
catch (Exception e) {
// MUST print.e(e); is there a better way?
return null;
}
}
/**
* throws only an exception when compilation fails
* @param pc
* @param page
* @return
* @throws PageException
*/
private Page loadPhysical(PageContext pc,Page page) throws TemplateException {
if(!mapping.hasPhysical()) return null;
ConfigWeb config=pc.getConfig();
PageContextImpl pci=(PageContextImpl) pc;
if((mapping.getInspectTemplate()==Config.INSPECT_NEVER || pci.isTrusted(page)) && isLoad(LOAD_PHYSICAL)) return page;
Resource srcFile = getPhyscalFile();
long srcLastModified = srcFile.lastModified();
if(srcLastModified==0L) return null;
// Page exists
if(page!=null) {
//if(page!=null && !recompileAlways) {
if(srcLastModified!=page.getSourceLastModified()) {
this.page=page=compile(config,mapping.getClassRootDirectory(),page,false,pc.ignoreScopes());
page.setPageSource(this);
page.setLoadType(LOAD_PHYSICAL);
}
}
// page doesn't exist
else {
Resource classRootDir=mapping.getClassRootDirectory();
Resource classFile=classRootDir.getRealResource(getJavaName()+".class");
boolean isNew=false;
// new class
if(flush || !classFile.exists()) {
this.page=page= compile(config,classRootDir,null,false,pc.ignoreScopes());
flush=false;
isNew=true;
}
// load page
else {
try {
this.page=page=newInstance(mapping.getPhysicalClass(this.getClassName()));
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
this.page=page=null;
}
if(page==null) this.page=page=compile(config,classRootDir,null,false,pc.ignoreScopes());
}
// check if version changed or lasMod
if(!isNew &&
(
srcLastModified!=page.getSourceLastModified()
||
page.getVersion()!=pc.getConfig().getFactory().getEngine().getInfo().getFullVersionInfo()
)) {
isNew=true;
this.page=page=compile(config,classRootDir,page,false,pc.ignoreScopes());
}
page.setPageSource(this);
page.setLoadType(LOAD_PHYSICAL);
}
pci.setPageUsed(page);
return page;
}
public void flush() {
page=null;
flush=true;
}
private boolean isLoad(byte load) {
return page!=null && load==page.getLoadType();
}
private Page compile(ConfigWeb config,Resource classRootDir, Page existing, boolean returnValue, boolean ignoreScopes) throws TemplateException {
try {
return _compile(config, classRootDir,existing,returnValue,ignoreScopes);
}
catch(RuntimeException re) {re.printStackTrace();
String msg=StringUtil.emptyIfNull(re.getMessage());
if(StringUtil.indexOfIgnoreCase(msg, "Method code too large!")!=-1) {
throw new TemplateException("There is too much code inside the template ["+getDisplayPath()+"], "+Constants.NAME+" was not able to break it into pieces, move parts of your code to an include or a external component/function",msg);
}
throw re;
}
catch(ClassFormatError e) {
String msg=StringUtil.emptyIfNull(e.getMessage());
if(StringUtil.indexOfIgnoreCase(msg, "Invalid method Code length")!=-1) {
throw new TemplateException("There is too much code inside the template ["+getDisplayPath()+"], "+Constants.NAME+" was not able to break it into pieces, move parts of your code to an include or a external component/function",msg);
}
throw new TemplateException("ClassFormatError:"+e.getMessage());
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
if(t instanceof TemplateException) throw (TemplateException)t;
throw new PageRuntimeException(Caster.toPageException(t));
}
}
private Page _compile(ConfigWeb config,Resource classRootDir, Page existing,boolean returnValue, boolean ignoreScopes) throws IOException, SecurityException, IllegalArgumentException, PageException {
ConfigWebImpl cwi=(ConfigWebImpl) config;
int dialect=getDialect();
long now;
if((getPhyscalFile().lastModified()+10000)>(now=System.currentTimeMillis()))
cwi.getCompiler().watch(this,now);//SystemUtil.get
synchronized(this) {
Result result = cwi.getCompiler().
compile(cwi,this,cwi.getTLDs(dialect),cwi.getFLDs(dialect),classRootDir,returnValue,ignoreScopes);
try {
Class<?> clazz = mapping.getPhysicalClass(getClassName(), result.barr);
return newInstance(clazz);
}
catch(Throwable t){
ExceptionUtil.rethrowIfNecessary(t);
PageException pe = Caster.toPageException(t);
pe.setExtendedInfo("failed to load template "+getDisplayPath());
throw pe;
}
}
}
private Page newInstance(Class clazz) throws SecurityException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Constructor<?> c = clazz.getConstructor(new Class[]{PageSource.class});
return (Page) c.newInstance(new Object[]{this});
}
/**
* return source path as String
* @return source path as String
*/
@Override
public String getDisplayPath() {
if(!mapping.hasArchive()) {
return StringUtil.toString(getPhyscalFile(), null);
}
else if(isLoad(LOAD_PHYSICAL)) {
return StringUtil.toString(getPhyscalFile(), null);
}
else if(isLoad(LOAD_ARCHIVE)) {
return StringUtil.toString(getArchiveSourcePath(), null);
}
else {
boolean pse = physcalExists();
boolean ase = archiveExists();
if(mapping.isPhysicalFirst()) {
if(pse)return getPhyscalFile().toString();
else if(ase)return getArchiveSourcePath();
return getPhyscalFile().toString();
}
if(ase)return getArchiveSourcePath();
else if(pse)return getPhyscalFile().toString();
return getArchiveSourcePath();
}
}
public boolean isComponent() {
String ext = ResourceUtil.getExtension(getRealpath(), "");
if(getDialect()==CFMLEngine.DIALECT_CFML)
return Constants.isCFMLComponentExtension(ext);
return Constants.isLuceeComponentExtension(ext);
}
/**
* return file object, based on physical path and realpath
* @return file Object
*/
private String getArchiveSourcePath() {
return "zip://"+mapping.getArchive().getAbsolutePath()+"!"+relPath;
}
/**
* return file object, based on physical path and realpath
* @return file Object
*/
@Override
public Resource getPhyscalFile() {
if(physcalSource==null) {
if(!mapping.hasPhysical()) {
return null;
}
Resource tmp = mapping.getPhysical().getRealResource(relPath);
physcalSource=ResourceUtil.toExactResource(tmp);
// fix if the case not match
if(!tmp.getAbsolutePath().equals(physcalSource.getAbsolutePath())) {
String relpath = physcalSource.getAbsolutePath().substring(mapping.getPhysical().getAbsolutePath().length());
// just a security!
if(relPath.equalsIgnoreCase(relpath)) {
this.relPath=relpath;
createClassAndPackage();
}
else {
// MUST remove this
/*aprint.e(
tmp+":"+physcalSource+":"+
mapping.getPhysical().getAbsolutePath()+":"+
relpath+":"+relPath);*/
}
}
}
return physcalSource;
}
public Resource getArchiveFile() {
if(archiveSource==null) {
if(!mapping.hasArchive()) return null;
String path="zip://"+mapping.getArchive().getAbsolutePath()+"!"+relPath;
archiveSource = ThreadLocalPageContext.getConfig().getResource(path);
}
return archiveSource;
}
/**
* merge to realpath to one
* @param mapping
* @param parentRealPath
* @param newRealPath
* @param isOutSide
* @return merged realpath
*/
private static String mergeRealPathes(Mapping mapping,String parentRealPath, String newRealPath, RefBoolean isOutSide) {
parentRealPath=pathRemoveLast(parentRealPath,isOutSide);
while(newRealPath.startsWith("../")) {
parentRealPath=pathRemoveLast(parentRealPath,isOutSide);
newRealPath=newRealPath.substring(3);
}
// check if come back
String path=parentRealPath.concat("/").concat(newRealPath);
if(path.startsWith("../")) {
int count=0;
do {
count++;
path=path.substring(3);
}while(path.startsWith("../"));
String strRoot=mapping.getPhysical().getAbsolutePath().replace('\\','/');
if(!StringUtil.endsWith(strRoot,'/')) {
strRoot+='/';
}
int rootLen=strRoot.length();
String[] arr=ListUtil.toStringArray(ListUtil.listToArray(path,'/'),"");//path.split("/");
int tmpLen;
for(int i=count;i>0;i--) {
if(arr.length>i) {
String tmp='/'+list(arr,0,i);
tmpLen=rootLen-tmp.length();
if(strRoot.lastIndexOf(tmp)==tmpLen && tmpLen>=0) {
StringBuffer rtn=new StringBuffer();
while(i<count-i) {
count--;
rtn.append("../");
}
isOutSide.setValue(rtn.length()!=0);
return (rtn.length()==0?"/":rtn.toString())+list(arr,i,arr.length);
}
}
}
}
return parentRealPath.concat("/").concat(newRealPath);
}
/**
* convert a String array to a string list, but only part of it
* @param arr String Array
* @param from start from here
* @param len how many element
* @return String list
*/
private static String list(String[] arr,int from, int len) {
StringBuffer sb=new StringBuffer();
for(int i=from;i<len;i++) {
sb.append(arr[i]);
if(i+1!=arr.length)sb.append('/');
}
return sb.toString();
}
/**
* remove the last elemtn of a path
* @param path path to remove last element from it
* @param isOutSide
* @return path with removed element
*/
private static String pathRemoveLast(String path, RefBoolean isOutSide) {
if(path.length()==0) {
isOutSide.setValue(true);
return "..";
}
else if(path.endsWith("..")){
isOutSide.setValue(true);
return path.concat("/..");//path+"/..";
}
return path.substring(0,path.lastIndexOf('/'));
}
@Override
public String getRealpath() {
return relPath;
}
@Override
public String getRealpathWithVirtual() {
if(mapping.getVirtual().length()==1 || mapping.ignoreVirtual())
return relPath;
return mapping.getVirtual()+relPath;
}
private String _getClassName() {
if(className==null) createClassAndPackage();
return className;
}
@Override
public String getClassName() {
if(className==null) createClassAndPackage();
if(packageName.length()==0) return className;
return packageName.concat(".").concat(className);
}
@Override
public String getFileName() {
if(fileName==null) createClassAndPackage();
return fileName;
}
public String getJavaName() {
if(javaName==null) createClassAndPackage();
return javaName;
}
private String _getPackageName() {
if(packageName==null) createClassAndPackage();
return packageName;
}
@Override
public String getComponentName() {
if(compName==null) createComponentName();
return compName;
}
private void createClassAndPackage() {
String str=relPath;
StringBuilder packageName=new StringBuilder();
StringBuilder javaName = new StringBuilder();
String[] arr=ListUtil.toStringArrayEL(ListUtil.listToArrayRemoveEmpty(str,'/'));
String varName,className=null,fileName=null;
for(int i=0;i<arr.length;i++) {
if(i==(arr.length-1)) {
int index=arr[i].lastIndexOf('.');
if(index!=-1){
String ext=arr[i].substring(index+1);
varName=StringUtil.toVariableName(arr[i].substring(0,index)+"_"+ext);
}
else varName=StringUtil.toVariableName(arr[i]);
varName=varName+(getDialect()==CFMLEngine.DIALECT_CFML?Constants.CFML_CLASS_SUFFIX:Constants.LUCEE_CLASS_SUFFIX);
className=varName.toLowerCase();
fileName=arr[i];
}
else {
varName=StringUtil.toVariableName(arr[i]);
if(i!=0) {
packageName.append('.');
}
packageName.append(varName);
}
javaName.append('/');
javaName.append(varName);
}
synchronized (this) {
this.packageName=packageName.toString().toLowerCase();
this.javaName=javaName.toString().toLowerCase();
this.fileName=fileName;
this.className=className;
}
}
private void createComponentName() {
Resource res = this.getPhyscalFile();
String str=null;
final String relPath=this.relPath;
if(res!=null) {
str=res.getAbsolutePath();
int begin=str.length()-relPath.length();
if(begin<0) { // TODO patch, analyze the complete functinality and improve
str=ListUtil.last(str, "\\/");
}
else {
str=str.substring(begin);
if(!str.equalsIgnoreCase(relPath)) {
str=relPath;
}
}
}
else str=relPath;
StringBuilder compName=new StringBuilder();
String[] arr;
// virtual part
if(!mapping.ignoreVirtual()) {
arr=ListUtil.toStringArrayEL(ListUtil.listToArrayRemoveEmpty(mapping.getVirtual(),"\\/"));
for(int i=0;i<arr.length;i++) {
if(compName.length()>0) compName.append('.');
compName.append(arr[i]);
}
}
// physical part
arr=ListUtil.toStringArrayEL(ListUtil.listToArrayRemoveEmpty(str,'/'));
for(int i=0;i<arr.length;i++) {
if(compName.length()>0) compName.append('.');
if(i==(arr.length-1)) {
compName.append(ResourceUtil.removeExtension(arr[i], arr[i]));
}
else compName.append(arr[i]);
}
synchronized (this) {
this.compName=compName.toString();
}
}
@Override
public Mapping getMapping() {
return mapping;
}
@Override
public boolean exists() {
if(mapping.isPhysicalFirst())
return physcalExists() || archiveExists();
return archiveExists() || physcalExists();
}
@Override
public boolean physcalExists() {
return ResourceUtil.exists(getPhyscalFile());
}
private boolean archiveExists() {
if(!mapping.hasArchive())return false;
try {
String clazz = getClassName();
if(clazz==null) return getArchiveFile().exists();
mapping.getArchiveClass(clazz);
return true;
}
catch(ClassNotFoundException cnfe){
return false;
}
catch (Exception e) {
return getArchiveFile().exists();
}
}
/**
* return the inputstream of the source file
* @return return the inputstream for the source from ohysical or archive
* @throws FileNotFoundException
*/
private InputStream getSourceAsInputStream() throws IOException {
if(!mapping.hasArchive()) return IOUtil.toBufferedInputStream(getPhyscalFile().getInputStream());
else if(isLoad(LOAD_PHYSICAL)) return IOUtil.toBufferedInputStream(getPhyscalFile().getInputStream());
else if(isLoad(LOAD_ARCHIVE)) {
StringBuffer name=new StringBuffer(_getPackageName().replace('.','/'));
if(name.length()>0)name.append("/");
name.append(getFileName());
return mapping.getArchiveResourceAsStream(name.toString());
}
else {
return null;
}
}
@Override
public String[] getSource() throws IOException {
//if(source!=null) return source;
InputStream is = getSourceAsInputStream();
if(is==null) return null;
try {
return IOUtil.toStringArray(IOUtil.getReader(is,getMapping().getConfig().getTemplateCharset()));
}
finally {
IOUtil.closeEL(is);
}
}
@Override
public boolean equals(Object obj) {
if(this==obj) return true;
if(obj instanceof PageSourceImpl)
return _getClassName().equals(((PageSourceImpl)obj)._getClassName());
if(obj instanceof PageSource)
return _getClassName().equals(ClassUtil.extractName(((PageSource)obj).getClassName()));
return false;
}
/**
* is given object equal to this
* @param other
* @return is same
*/
public boolean equals(PageSource ps) {
if(this==ps) return true;
if(ps instanceof PageSourceImpl)
return _getClassName().equals(((PageSourceImpl)ps)._getClassName());
return _getClassName().equals(ClassUtil.extractName(ps.getClassName()));
}
@Override
public PageSource getRealPage(String realPath) {
if(realPath.equals(".") || realPath.equals(".."))realPath+='/';
else realPath=realPath.replace('\\','/');
RefBoolean _isOutSide=new RefBooleanImpl(isOutSide);
if(realPath.indexOf('/')==0) {
_isOutSide.setValue(false);
}
else if(realPath.startsWith("./")) {
realPath=mergeRealPathes(mapping,this.relPath, realPath.substring(2),_isOutSide);
}
else {
realPath=mergeRealPathes(mapping,this.relPath, realPath,_isOutSide);
}
return mapping.getPageSource(realPath,_isOutSide.toBooleanValue());
}
@Override
public final void setLastAccessTime(long lastAccess) {
this.lastAccess=lastAccess;
}
@Override
public final long getLastAccessTime() {
return lastAccess;
}
@Override
public final void setLastAccessTime() {
accessCount.plus(1);
this.lastAccess=System.currentTimeMillis();
}
@Override
public final int getAccessCount() {
return accessCount.toInt();
}
@Override
public Resource getResource() {
Resource p = getPhyscalFile();
Resource a = getArchiveFile();
if(mapping.isPhysicalFirst()){
if(a==null) return p;
if(p==null) return a;
if(p.exists()) return p;
if(a.exists()) return a;
return p;
}
if(p==null) return a;
if(a==null) return p;
if(a.exists()) return a;
if(p.exists()) return p;
return a;
//return getArchiveFile();
}
@Override
public Resource getResourceTranslated(PageContext pc) throws ExpressionException {
Resource res = null;
if(!isLoad(LOAD_ARCHIVE)) res=getPhyscalFile();
// there is no physical resource
if(res==null){
String path=getDisplayPath();
if(path!=null){
if(path.startsWith("ra://"))
path="zip://"+path.substring(5);
res=ResourceUtil.toResourceNotExisting(pc, path,false,false);
}
}
return res;
}
public void clear() {
if(page!=null){
page=null;
}
}
/**
* clear page, but only when page use the same clasloader as provided
* @param cl
*/
public void clear(ClassLoader cl) {
if(page!=null && page.getClass().getClassLoader().equals(cl)){
page=null;
}
}
public boolean isLoad() {
return page!=null;////load!=LOAD_NONE;
}
@Override
public String toString() {
return getDisplayPath();
}
public static PageSource best(PageSource[] arr) {
if(ArrayUtil.isEmpty(arr)) return null;
if(arr.length==1)return arr[0];
for(int i=0;i<arr.length;i++) {
if(pageExist(arr[i])) return arr[i];
}
return arr[0];
}
public static boolean pageExist(PageSource ps) {
return (ps.getMapping().isTrusted() && ((PageSourceImpl)ps).isLoad()) || ps.exists();
}
public static Page loadPage(PageContext pc,PageSource[] arr,Page defaultValue) throws PageException {
if(ArrayUtil.isEmpty(arr)) return null;
Page p;
for(int i=0;i<arr.length;i++) {
p=arr[i].loadPageThrowTemplateException(pc,false,(Page)null);
if(p!=null) return p;
}
return defaultValue;
}
public static Page loadPage(PageContext pc,PageSource[] arr) throws PageException {
if(ArrayUtil.isEmpty(arr)) return null;
Page p;
for(int i=0;i<arr.length;i++) {
p=arr[i].loadPageThrowTemplateException(pc,false,(Page)null);
if(p!=null) return p;
}
throw new MissingIncludeException(arr[0]);
}
@Override
public int getDialect() {
Config c = getMapping().getConfig();
if(!((ConfigImpl)c).allowLuceeDialect()) return CFMLEngine.DIALECT_CFML;
// MUST improve performance on this
ConfigWeb cw=null;
String ext=ResourceUtil.getExtension(relPath, Constants.getCFMLComponentExtension());
if(c instanceof ConfigWeb)
cw=(ConfigWeb) c;
else {
c=ThreadLocalPageContext.getConfig();
if(c instanceof ConfigWeb)
cw=(ConfigWeb) c;
}
if(cw!=null) {
return ((CFMLFactoryImpl)cw.getFactory())
.toDialect(ext,CFMLEngine.DIALECT_CFML);
}
return ConfigWebUtil.toDialect(ext, CFMLEngine.DIALECT_CFML);
}
/**
* return if the PageSource represent a template (no component,no interface)
* @param pc
* @param ps
* @return
* @throws PageException
*/
public static boolean isTemplate(PageContext pc,PageSource ps, boolean defaultValue) {
try {
return !(ps.loadPage(pc, false) instanceof CIPage);
} catch (PageException e) {e.printStackTrace();
return defaultValue;
}
}
@Override
public boolean executable() {
return (getMapping().getInspectTemplate()==Config.INSPECT_NEVER && isLoad()) || exists();
}
}