package railo.runtime.component;
import java.util.Map;
import javax.servlet.jsp.tagext.BodyContent;
import railo.commons.io.res.Resource;
import railo.commons.io.res.filter.DirectoryResourceFilter;
import railo.commons.io.res.filter.ExtensionResourceFilter;
import railo.commons.io.res.filter.OrResourceFilter;
import railo.commons.io.res.filter.ResourceFilter;
import railo.commons.lang.StringUtil;
import railo.runtime.Component;
import railo.runtime.ComponentImpl;
import railo.runtime.ComponentPage;
import railo.runtime.InterfaceImpl;
import railo.runtime.InterfacePage;
import railo.runtime.Mapping;
import railo.runtime.MappingImpl;
import railo.runtime.Page;
import railo.runtime.PageContext;
import railo.runtime.PageContextImpl;
import railo.runtime.PageSource;
import railo.runtime.PageSourceImpl;
import railo.runtime.config.ConfigImpl;
import railo.runtime.debug.DebugEntryTemplate;
import railo.runtime.exp.ApplicationException;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.writer.BodyContentUtil;
public class ComponentLoader {
private static final ResourceFilter DIR_OR_EXT=new OrResourceFilter(new ResourceFilter[]{DirectoryResourceFilter.FILTER,new ExtensionResourceFilter(".cfc")});
public static ComponentImpl loadComponent(PageContext pc,PageSource child,String rawPath, Boolean searchLocal, Boolean searchRoot) throws PageException {
return (ComponentImpl)load(pc,child, rawPath, searchLocal, searchRoot,null,false);
}
public static InterfaceImpl loadInterface(PageContext pc,PageSource child,String rawPath, Map interfaceUDFs) throws PageException {
return (InterfaceImpl)load(pc,child, rawPath, Boolean.TRUE, Boolean.TRUE,interfaceUDFs,false);
}
public static Page loadPage(PageContext pc,PageSource child,String rawPath, Boolean searchLocal, Boolean searchRoot) throws PageException {
return (Page)load(pc, child,rawPath, searchLocal, searchRoot,null,true);
}
private static Object load(PageContext pc,PageSource child,String rawPath, Boolean searchLocal, Boolean searchRoot, Map interfaceUDFs, boolean returnPage) throws PageException {
ConfigImpl config=(ConfigImpl) pc.getConfig();
boolean doCache=config.useComponentPathCache();
//print.o(rawPath);
//app-String appName=pc.getApplicationContext().getName();
rawPath=rawPath.trim().replace('\\','/');
String path=(rawPath.indexOf("./")==-1)?rawPath.replace('.','/'):rawPath;
String pathWithCFC=path.concat(".cfc");
boolean isRealPath=!StringUtil.startsWith(pathWithCFC,'/');
PageSource currPS = pc.getCurrentPageSource();
Page currP=((PageSourceImpl)currPS).loadPage(pc,(Page)null);
PageSource ps=null;
Page page=null;
if(searchLocal==null)
searchLocal=Caster.toBoolean(config.getComponentLocalSearch());
if(searchRoot==null)
searchRoot=Caster.toBoolean(config.getComponentRootSearch());
//boolean searchLocal=config.getComponentLocalSearch();
// CACHE
// check local in cache
String localCacheName=null;
if(searchLocal && isRealPath){
localCacheName=currPS.getDisplayPath().replace('\\', '/');
localCacheName=localCacheName.substring(0,localCacheName.lastIndexOf('/')+1).concat(pathWithCFC);
if(doCache){
page=config.getCachedPage(pc, localCacheName);
if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
// check import cache
if(doCache && isRealPath){
ImportDefintion impDef = config.getComponentDefaultImport();
ImportDefintion[] impDefs=currP==null?new ImportDefintion[0]:currP.getImportDefintions();
int i=-1;
do{
if(impDef.isWildcard() || impDef.getName().equalsIgnoreCase(path)){
page=config.getCachedPage(pc, "import:"+impDef.getPackageAsPath()+pathWithCFC);
if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
//app-page=config.getCachedPage(pc, "import:"+appName+":"+impDef.getPackageAsPath()+pathWithCFC);
//app-if(page!=null) return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
impDef=++i<impDefs.length?impDefs[i]:null;
}
while(impDef!=null);
}
if(doCache) {
// check global in cache
page=config.getCachedPage(pc, pathWithCFC);
if(page!=null) return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
// get pages from application mappings
//app-page=config.getCachedPage(pc, ":"+appName+":"+pathWithCFC);
//app-if(page!=null) return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
// SEARCH
// search from local
if(searchLocal && isRealPath) {
// check realpath
PageSource[] arr = ((PageContextImpl)pc).getRelativePageSources(pathWithCFC);
page=PageSourceImpl.loadPage(pc, arr,null);
if(page!=null){
if(doCache)config.putCachedPageSource(localCacheName, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
// search with imports
Mapping[] cMappings = config.getComponentMappings();
if(isRealPath){
ImportDefintion impDef = config.getComponentDefaultImport();
ImportDefintion[] impDefs=currP==null?new ImportDefintion[0]:currP.getImportDefintions();
PageSource[] arr;
int i=-1;
do{
if(impDef.isWildcard() || impDef.getName().equalsIgnoreCase(path)){
// search from local first
if(searchLocal){
arr = ((PageContextImpl)pc).getRelativePageSources(impDef.getPackageAsPath()+pathWithCFC);
page=PageSourceImpl.loadPage(pc, arr,null);
if(page!=null) {
if(doCache)config.putCachedPageSource("import:"+impDef.getPackageAsPath()+pathWithCFC, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
// search local component mappings
/*app-if(lcMappings!=null) {
Mapping m;
for(int y=0;y<lcMappings.length;y++){
m=lcMappings[y];
String key=appName+":"+impDef.getPackageAsPath()+pathWithCFC;
ps=m.getPageSource(impDef.getPackageAsPath()+pathWithCFC);
page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null);
if(page!=null) {
if(doCache)config.putCachedPageSource("import:"+key, page.getPageSource());
return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
}*/
// search mappings and webroot
page=PageSourceImpl.loadPage(pc, ((PageContextImpl)pc).getPageSources("/"+impDef.getPackageAsPath()+pathWithCFC), null);
if(page!=null){
String key=impDef.getPackageAsPath()+pathWithCFC;
if(doCache && !((MappingImpl)page.getPageSource().getMapping()).isAppMapping())
config.putCachedPageSource("import:"+key, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
// search component mappings
Mapping m;
for(int y=0;y<cMappings.length;y++){
m=cMappings[y];
ps=m.getPageSource(impDef.getPackageAsPath()+pathWithCFC);
page=((PageSourceImpl)ps).loadPage(pc,(Page)null);
if(page!=null) {
if(doCache)config.putCachedPageSource("import:"+impDef.getPackageAsPath()+pathWithCFC, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
}
impDef=++i<impDefs.length?impDefs[i]:null;
}
while(impDef!=null);
}
String p;
if(isRealPath) p='/'+pathWithCFC;
else p=pathWithCFC;
// search local component mappings
/* app-if(lcMappings!=null) {
Mapping m;
for(int i=0;i<lcMappings.length;i++){
m=lcMappings[i];
ps=m.getPageSource(p);
page=((PageSourceImpl)ps).loadPage(pc,pc.getConfig(),null);
String key=":"+appName+":"+pathWithCFC;
if(page!=null){
if(doCache)config.putCachedPageSource(key, page.getPageSource());
return load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
}*/
// search mappings and webroot
page=PageSourceImpl.loadPage(pc,((PageContextImpl)pc).getPageSources(p),null);
if(page!=null){
String key=pathWithCFC;
if(doCache && !((MappingImpl)page.getPageSource().getMapping()).isAppMapping())
config.putCachedPageSource(key, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
// search component mappings
Mapping m;
for(int i=0;i<cMappings.length;i++){
m=cMappings[i];
ps=m.getPageSource(p);
page=((PageSourceImpl)ps).loadPage(pc,(Page)null);
// recursive search
if(page==null && config.doComponentDeepSearch() && m.hasPhysical() && path.indexOf('/')==-1) {
String _path=getPagePath(pc, m.getPhysical(), null,pathWithCFC,DirectoryResourceFilter.FILTER);
if(_path!=null) {
ps=m.getPageSource(_path);
page=((PageSourceImpl)ps).loadPage(pc,(Page)null);
doCache=false;// do not cache this, it could be ambigous
}
}
if(page!=null){
if(doCache)config.putCachedPageSource(pathWithCFC, page.getPageSource());
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
// search relative to active cfc (this get not cached because the cache get ambigous if we do)
if(searchLocal && isRealPath) {
if(child==null) {
Component cfc = pc.getActiveComponent();
if(cfc!=null) child = cfc.getPageSource();
}
if(child!=null) {
ps=child.getRealPage(pathWithCFC);
if(ps!=null) {
page=((PageSourceImpl)ps).loadPage(pc,(Page)null);
if(page!=null){
return returnPage?page:load(pc,page,page.getPageSource(),trim(path.replace('/', '.')),isRealPath,interfaceUDFs);
}
}
}
}
// translate cfide. to org.railo.cfml
if(StringUtil.startsWithIgnoreCase(rawPath, "cfide.")) {
String rpm="org.railo.cfml."+rawPath.substring(6);
try{
return load(pc,child,rpm, searchLocal, searchRoot, interfaceUDFs,returnPage);
}
catch(ExpressionException ee){
throw new ExpressionException("invalid "+(interfaceUDFs==null?"component":"interface")+" definition, can't find "+rawPath+" or "+rpm);
}
}
throw new ExpressionException("invalid "+(interfaceUDFs==null?"component":"interface")+" definition, can't find "+rawPath);
}
private static String getPagePath(PageContext pc, Resource res, String dir,String name, ResourceFilter filter) {
if(res.isFile()) {
if(res.getName().equalsIgnoreCase(name)) {
return dir+res.getName();
}
}
else if(res.isDirectory()) {
Resource[] _dir = res.listResources(filter);
if(_dir!=null){
if(dir==null) dir="/";
else dir=dir+res.getName()+"/";
String path;
for(int i=0;i<_dir.length;i++){
path=getPagePath(pc, _dir[i],dir, name,DIR_OR_EXT);
if(path!=null) return path;
}
}
}
return null;
}
private static String trim(String str) {
if(StringUtil.startsWith(str, '.'))str=str.substring(1);
return str;
}
/*private static Page getPage(PageContext pc,String path, RefBoolean isRealPath, boolean searchLocal) throws PageException {
Page page=null;
isRealPath.setValue(!StringUtil.startsWith(path,'/'));
// search from local
PageSource[] arr;
if(searchLocal && isRealPath.toBooleanValue()){
arr = ((PageContextImpl)pc).getRelativePageSources(path);
page=PageSourceImpl.loadPage(pc, arr, null);
}
// search from root
if(page==null) {
if(isRealPath.toBooleanValue()){
isRealPath.setValue(false);
arr=((PageContextImpl)pc).getPageSources('/'+path);
}
else {
arr=((PageContextImpl)pc).getPageSources(path);
}
page=PageSourceImpl.loadPage(pc,arr,null);
}
return page;
}*/
//
public static ComponentImpl loadComponent(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, boolean silent) throws PageException {
/*if(page==null && ps instanceof PageSourceImpl) {
page=((PageSourceImpl)ps).getPage();
}*/
if(silent) {
// TODO is there a more direct way
BodyContent bc = pc.pushBody();
try {
return loadComponent(pc,page,ps,callPath,isRealPath);
}
finally {
BodyContentUtil.clearAndPop(pc, bc);
}
}
return loadComponent(pc,page,ps,callPath,isRealPath);
}
private static Object load(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, Map interfaceUDFs) throws PageException {
if(interfaceUDFs==null) return loadComponent(pc,page, ps,callPath, isRealPath);
return loadInterface(pc,page, ps, callPath, isRealPath, interfaceUDFs);
}
public static Page loadPage(PageContext pc,PageSource ps, boolean forceReload) throws PageException {
if(pc.getConfig().debug()) {
DebugEntryTemplate debugEntry=pc.getDebugger().getEntry(pc,ps);
pc.addPageSource(ps,true);
int currTime=pc.getExecutionTime();
long exeTime=0;
long time=System.currentTimeMillis();
try {
debugEntry.updateFileLoadTime((int)(System.currentTimeMillis()-time));
exeTime=System.currentTimeMillis();
return ((PageSourceImpl)ps).loadPage(pc,forceReload);
}
finally {
int diff= ((int)(System.currentTimeMillis()-exeTime)-(pc.getExecutionTime()-currTime));
pc.setExecutionTime(pc.getExecutionTime()+(int)(System.currentTimeMillis()-time));
debugEntry.updateExeTime(diff);
pc.removeLastPageSource(true);
}
}
// no debug
pc.addPageSource(ps,true);
try {
return ((PageSourceImpl)ps).loadPage(pc,forceReload);
}
finally {
pc.removeLastPageSource(true);
}
}
public static ComponentImpl loadComponent(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath) throws PageException {
ComponentImpl rtn=null;
if(pc.getConfig().debug()) {
DebugEntryTemplate debugEntry=pc.getDebugger().getEntry(pc,ps);
pc.addPageSource(ps,true);
int currTime=pc.getExecutionTime();
long exeTime=0;
long time=System.nanoTime();
try {
debugEntry.updateFileLoadTime((int)(System.nanoTime()-time));
exeTime=System.nanoTime();
if(page==null)page=((PageSourceImpl)ps).loadPage(pc);
rtn=initComponent(pc,page,callPath,isRealPath);
}
finally {
if(rtn!=null)rtn.setLoaded(true);
int diff= ((int)(System.nanoTime()-exeTime)-(pc.getExecutionTime()-currTime));
pc.setExecutionTime(pc.getExecutionTime()+(int)(System.nanoTime()-time));
debugEntry.updateExeTime(diff);
pc.removeLastPageSource(true);
}
}
// no debug
else {
pc.addPageSource(ps,true);
try {
if(page==null)page=((PageSourceImpl)ps).loadPage(pc);
rtn=initComponent(pc,page,callPath,isRealPath);
}
finally {
if(rtn!=null)rtn.setLoaded(true);
pc.removeLastPageSource(true);
}
}
return rtn;
}
public static InterfaceImpl loadInterface(PageContext pc,Page page, PageSource ps,String callPath, boolean isRealPath, Map interfaceUDFs) throws PageException {
InterfaceImpl rtn=null;
if(pc.getConfig().debug()) {
DebugEntryTemplate debugEntry=pc.getDebugger().getEntry(pc,ps);
pc.addPageSource(ps,true);
int currTime=pc.getExecutionTime();
long exeTime=0;
long time=System.nanoTime();
try {
debugEntry.updateFileLoadTime((int)(System.nanoTime()-time));
exeTime=System.nanoTime();
if(page==null)page=((PageSourceImpl)ps).loadPage(pc);
rtn=initInterface(pc,page,callPath,isRealPath,interfaceUDFs);
}
finally {
int diff= ((int)(System.nanoTime()-exeTime)-(pc.getExecutionTime()-currTime));
pc.setExecutionTime(pc.getExecutionTime()+(int)(System.nanoTime()-time));
debugEntry.updateExeTime(diff);
pc.removeLastPageSource(true);
}
}
// no debug
else {
pc.addPageSource(ps,true);
try {
if(page==null)page=((PageSourceImpl)ps).loadPage(pc);
rtn=initInterface(pc,page,callPath,isRealPath,interfaceUDFs);
}
finally {
pc.removeLastPageSource(true);
}
}
return rtn;
}
/* *
* load a component
* @param rawPath
* @return loaded component
* @throws PageException
* /
public static InterfaceImpl loadInterface(PageContext pc,String rawPath,boolean allowRemovingExt, Map interfaceUDFs) throws PageException {
// MUSTMUST sync code with extends
String fullName=rawPath;
boolean hasRemovedExt=false;
fullName=fullName.trim().replace('\\','/').replace('.','/');
String path=fullName.concat(".cfc");
boolean isRealPath=!StringUtil.startsWith(fullName,'/');
PageSource res=pc.getRelativePageSource(path);
Page page=null;
//try {
page=((PageSourceImpl)res).loadPage(pc,pc.getConfig(),null);
if(page==null && isRealPath) {
isRealPath=false;
PageSource resOld = res;
res=pc.getPageSource('/'+path);
page=((PageSourceImpl)res).loadPage(pc,pc.getConfig(),null);
if(page==null) {
if(hasRemovedExt)return loadInterface(pc,rawPath, false,interfaceUDFs);
String detail="search for "+res.getDisplayPath();
if(resOld!=null)detail+=" and "+resOld.getDisplayPath();
if(StringUtil.startsWithIgnoreCase(rawPath, "cfide.")) {
String rpm="org.railo.cfml."+rawPath.substring(6);
try{
return loadInterface(pc,rpm,allowRemovingExt, interfaceUDFs);
}
catch(ExpressionException ee){
throw new ExpressionException("invalid interface definition, can't find "+rawPath+" or "+rpm,detail);
}
}
else throw new ExpressionException("invalid interface definition, can't find "+rawPath,detail);
}
}
return loadInterface(pc,page,res,fullName.replace('/', '.'),isRealPath,interfaceUDFs);
}*/
private static InterfaceImpl initInterface(PageContext pc,Page page,String callPath,boolean isRealPath, Map interfaceUDFs) throws PageException {
if(!(page instanceof InterfacePage))
throw new ApplicationException("invalid interface definition ["+callPath+"]");
InterfacePage ip=(InterfacePage)page;
InterfaceImpl i = ip.newInstance(callPath,isRealPath,interfaceUDFs);
return i;
}
private static ComponentImpl initComponent(PageContext pc,Page page,String callPath,boolean isRealPath) throws PageException {
if(!(page instanceof ComponentPage)){
if(page instanceof InterfacePage)
throw new ApplicationException("can not instantiate interface ["+callPath+"] as a component");
throw new ApplicationException("invalid component definition ["+callPath+"]");
}
ComponentPage cp = (ComponentPage)page;
ComponentImpl c = cp.newInstance(pc,callPath,isRealPath);
c.setInitalized(true);
return c;
}
}