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