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}