001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.commons.lang;
020
021import java.io.IOException;
022import java.util.zip.ZipEntry;
023import java.util.zip.ZipInputStream;
024
025import lucee.commons.io.IOUtil;
026import lucee.commons.io.res.Resource;
027import lucee.commons.io.res.filter.DirectoryResourceFilter;
028import lucee.commons.io.res.filter.ExtensionResourceFilter;
029import lucee.commons.io.res.filter.ResourceFilter;
030import lucee.runtime.Mapping;
031import lucee.runtime.MappingImpl;
032import lucee.runtime.PageContext;
033import lucee.runtime.PageSource;
034import lucee.runtime.config.Config;
035import lucee.runtime.config.ConfigWebUtil;
036import lucee.runtime.engine.ThreadLocalPageContext;
037import lucee.runtime.functions.system.ExpandPath;
038import lucee.transformer.bytecode.util.ASMUtil;
039import lucee.transformer.bytecode.util.SourceNameClassVisitor.SourceInfo;
040
041public class MappingUtil {
042        //private static final ResourceFilter EXT=new ExtensionResourceFilter(".cfc");
043        //private static final ResourceFilter DIR_OR_EXT=new OrResourceFilter(new ResourceFilter[]{DirectoryResourceFilter.FILTER,EXT});
044
045        
046        public static PageSource searchMappingRecursive(Mapping mapping, String name, boolean onlyCFC) {
047                if(name.indexOf('/')==-1) { // TODO handle this as well?
048                        Config config = mapping.getConfig();
049                        ExtensionResourceFilter ext =null;
050                        if(onlyCFC) ext=new ExtensionResourceFilter(new String[]{config.getCFCExtension()},true,true);
051                        else {
052                                ext=new ExtensionResourceFilter(config.getCFMLExtensions(),true,true);
053                                ext.addExtension(config.getCFCExtension());
054                        }
055                        
056                        if(mapping.isPhysicalFirst()) {
057                                PageSource ps = searchPhysical(mapping,name,ext);
058                                if(ps!=null) return ps;
059                                ps=searchArchive(mapping,name,onlyCFC);
060                                if(ps!=null) return ps;
061                        }
062                        else {
063                                PageSource ps=searchArchive(mapping,name,onlyCFC);
064                                if(ps!=null) return ps;
065                                ps = searchPhysical(mapping,name,ext);
066                                if(ps!=null) return ps;
067                        }
068                }
069                return null;
070        }
071
072        private static PageSource searchArchive(Mapping mapping, String name, boolean onlyCFC) {
073                Resource archive = mapping.getArchive();
074                if(archive!=null && archive.isFile()) {
075                        ClassLoader cl = mapping.getClassLoaderForArchive();
076                        ZipInputStream zis = null;
077                        try{
078                                zis = new ZipInputStream(archive.getInputStream());
079                                ZipEntry entry;
080                                Class clazz;
081                                while((entry=zis.getNextEntry())!=null){
082                                        if(entry.isDirectory() || !entry.getName().endsWith(".class")) continue;
083                                        clazz=toClass(cl,entry.getName());
084                                        
085                                        if(clazz==null) continue;
086                                        SourceInfo srcInf = ASMUtil.getSourceInfo(mapping.getConfig(),clazz,onlyCFC);
087                                        if(name.equalsIgnoreCase(srcInf.name)) {
088                                                PageSource ps = mapping.getPageSource(srcInf.relativePath);
089                                                //Page page = ((PageSourceImpl)ps).loadPage(pc,(Page)null);
090                                                return ps;
091                                        }
092                                }
093                                
094                                
095                                
096                        }
097                        catch(IOException ioe) {
098                                ioe.printStackTrace();
099                        }
100                        finally {
101                                IOUtil.closeEL(zis);
102                        }
103                        
104                }
105                // TODO Auto-generated method stub
106                return null;
107        }
108        
109        private static Class toClass(ClassLoader cl,String name) {
110                name=name.replace('/', '.').substring(0,name.length()-6);
111                try {
112                        return cl.loadClass(name);
113                }
114                catch (ClassNotFoundException e) {}
115                return null;
116        }
117
118        
119        
120        
121        
122
123        private static PageSource searchPhysical(Mapping mapping, String name, ResourceFilter filter) {
124                Resource physical = mapping.getPhysical();
125                if(physical!=null) {
126                        String _path=searchPhysical(mapping.getPhysical(), null,name,filter,true);
127                        
128                        if(_path!=null) {
129                                PageSource ps = mapping.getPageSource(_path);
130                                //Page page = ((PageSourceImpl)ps).loadPage(pc,(Page)null);
131                                return ps;
132                        }
133                }
134                return null;
135        }
136        
137        private static String searchPhysical(Resource res, String dir,String name, ResourceFilter filter, boolean top) {
138                if(res.isFile()) {
139                        if(res.getName().equalsIgnoreCase(name)) {
140                                return dir+res.getName();
141                        }
142                }
143                else if(res.isDirectory()) {
144                        Resource[] _dir = res.listResources(top?DirectoryResourceFilter.FILTER:filter);
145                        if(_dir!=null){
146                                if(dir==null) dir="/";
147                                else dir=dir+res.getName()+"/";
148                                String path;
149                                for(int i=0;i<_dir.length;i++){
150                                        path=searchPhysical(_dir[i],dir, name,filter,false);
151                                        if(path!=null) return path;
152                                }
153                        }
154                }
155                
156                return null;
157        }
158        
159        public static SourceInfo getMatch(PageContext pc, StackTraceElement trace) {
160                return getMatch(pc,null, trace);
161                
162        }
163
164        public static SourceInfo getMatch(Config config, StackTraceElement trace) {
165                return getMatch(null,config, trace);
166        }
167        
168        public static SourceInfo getMatch(PageContext pc,Config config, StackTraceElement trace) {
169                if(pc==null && config==null)
170                        config=ThreadLocalPageContext.getConfig();
171                if(trace.getFileName()==null) return null;
172                
173                //PageContext pc = ThreadLocalPageContext.get();
174                Mapping[] mappings = pc!=null? ConfigWebUtil.getAllMappings(pc):ConfigWebUtil.getAllMappings(config);
175                if(pc!=null) config=pc.getConfig();
176                
177                Mapping mapping;
178                Class clazz;
179                for(int i=0;i<mappings.length;i++){
180                        mapping=mappings[i];
181                        //print.e("virtual:"+mapping.getVirtual()+"+"+trace.getClassName());
182                        // look for the class in that mapping
183                        clazz=((MappingImpl)mapping).loadClass(trace.getClassName());
184                        if(clazz==null) continue;
185                        
186                        // classname is not distinct, because of that we must check class content
187                        try {
188                                SourceInfo si = ASMUtil.getSourceInfo(config, clazz, false);
189                                if(si!=null) {
190                                        if(trace.getFileName()!=null && trace.getFileName().equals(si.absolutePath(pc)))
191                                                return si;
192                                }
193                        }
194                        catch (IOException e) {}
195                        
196                        
197                }
198                return null;
199        }
200}