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