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.transformer.cfml.evaluator.impl; 020 021import java.io.ByteArrayInputStream; 022import java.io.ByteArrayOutputStream; 023import java.io.IOException; 024import java.util.zip.ZipEntry; 025import java.util.zip.ZipInputStream; 026 027import lucee.commons.io.IOUtil; 028import lucee.commons.io.res.Resource; 029import lucee.commons.io.res.util.ResourceUtil; 030import lucee.commons.lang.Md5; 031import lucee.commons.lang.StringUtil; 032import lucee.commons.lang.SystemOut; 033import lucee.loader.util.Util; 034import lucee.runtime.PageSource; 035import lucee.runtime.config.Config; 036import lucee.runtime.config.ConfigImpl; 037import lucee.runtime.config.ConfigWebUtil; 038import lucee.runtime.exp.TemplateException; 039import lucee.transformer.bytecode.statement.tag.Attribute; 040import lucee.transformer.bytecode.statement.tag.Tag; 041import lucee.transformer.bytecode.statement.tag.TagImport; 042import lucee.transformer.bytecode.util.ASMUtil; 043import lucee.transformer.cfml.Data; 044import lucee.transformer.cfml.evaluator.EvaluatorException; 045import lucee.transformer.cfml.evaluator.EvaluatorSupport; 046import lucee.transformer.library.function.FunctionLib; 047import lucee.transformer.library.tag.CustomTagLib; 048import lucee.transformer.library.tag.TagLib; 049import lucee.transformer.library.tag.TagLibException; 050import lucee.transformer.library.tag.TagLibFactory; 051import lucee.transformer.library.tag.TagLibTag; 052import lucee.transformer.util.CFMLString; 053 054 055/** 056 * 057 */ 058public final class Import extends EvaluatorSupport { 059 060 public void evaluate(Tag tag,TagLibTag libTag) throws EvaluatorException { 061 } 062 063 /** 064 * @see lucee.transformer.cfml.evaluator.Evaluator#execute(lucee.runtime.config.Config, org.w3c.dom.Element, lucee.transformer.library.tag.TagLibTag, lucee.transformer.library.function.FunctionLib[], lucee.transformer.util.CFMLString) 065 */ 066 public TagLib execute(Config config,Tag tag, TagLibTag libTag, FunctionLib[] flibs,Data data) throws TemplateException { 067 TagImport ti=(TagImport) tag; 068 Attribute p = tag.getAttribute("prefix"); 069 Attribute t = tag.getAttribute("taglib"); 070 Attribute path = tag.getAttribute("path"); 071 072 if(p!=null || t!=null){ 073 if(p==null) 074 throw new TemplateException(data.cfml,"Wrong Context, missing attribute [prefix] for tag "+tag.getFullname()); 075 if(t==null) 076 throw new TemplateException(data.cfml,"Wrong Context, missing attribute [taglib] for tag "+tag.getFullname()); 077 078 if(path!=null) 079 throw new TemplateException(data.cfml,"Wrong context, you have an invalid attributes constellation for the tag "+tag.getFullname()+", " + 080 "you cannot mix attribute [path] with attributes [taglib] and [prefix]"); 081 082 return executePT(config, tag, libTag, flibs, data.cfml); 083 } 084 if(path==null) throw new TemplateException(data.cfml,"Wrong context, you have an invalid attributes constellation for the tag "+tag.getFullname()+", " + 085 "you need to define the attributes [prefix] and [taglib], the attribute [path] or simply define a attribute value"); 086 087 String strPath=ASMUtil.getAttributeString(tag,"path",null); 088 if(strPath==null) throw new TemplateException(data.cfml,"attribute [path] must be a constant value"); 089 ti.setPath(strPath); 090 091 return null; 092 093 } 094 095 private TagLib executePT(Config config,Tag tag, TagLibTag libTag, FunctionLib[] flibs,CFMLString cfml) throws TemplateException { 096 097 // Attribute prefix 098 String nameSpace=ASMUtil.getAttributeString(tag,"prefix",null); 099 if(nameSpace==null) throw new TemplateException(cfml,"attribute [prefix] must be a constant value"); 100 nameSpace=nameSpace.trim(); 101 String nameSpaceSeparator=StringUtil.isEmpty(nameSpace)?"":":"; 102 103 104 // Attribute taglib 105 String textTagLib=ASMUtil.getAttributeString(tag,"taglib",null); 106 if(textTagLib==null) throw new TemplateException(cfml,"attribute [taglib] must be a constant value"); 107 108 textTagLib=textTagLib.replace('\\','/'); 109 textTagLib=ConfigWebUtil.replacePlaceholder(textTagLib, config); 110 // File TagLib 111 String ext=ResourceUtil.getExtension(textTagLib,null); 112 boolean hasTldExtension="tld".equalsIgnoreCase(ext) || "tldx".equalsIgnoreCase(ext); 113 114 Resource absFile=config.getResource(textTagLib); 115 // TLD 116 if(absFile.isFile()) return _executeTLD(config,absFile,nameSpace,nameSpaceSeparator,cfml); 117 // CTD 118 //else if(absFile.isDirectory()) return _executeCTD(absFile,textPrefix); 119 120 121 // Second Change 122 if(textTagLib.startsWith("/")){ 123 //config.getPhysical(textTagLib); 124 PageSource ps = ((ConfigImpl)config).getPageSourceExisting(null,null,textTagLib,false,false,true,false); 125 126 //config.getConfigDir() 127 if(ps!=null) { 128 if(ps.physcalExists()) { 129 Resource file = ps.getPhyscalFile(); 130 // TLD 131 if(file.isFile()) return _executeTLD(config,file,nameSpace,nameSpaceSeparator,cfml); 132 } 133 // CTD 134 if(!hasTldExtension)return _executeCTD(textTagLib,nameSpace,nameSpaceSeparator); 135 } 136 } 137 else { 138 Resource sourceFile=cfml.getPageSource().getPhyscalFile(); 139 if(sourceFile!=null) { 140 Resource file = sourceFile.getParentResource().getRealResource(textTagLib); 141 // TLD 142 if(file.isFile()) return _executeTLD(config,file,nameSpace,nameSpaceSeparator,cfml); 143 // CTD 144 if(!hasTldExtension)return _executeCTD(textTagLib,nameSpace,nameSpaceSeparator); 145 } 146 } 147 throw new TemplateException(cfml,"invalid definition of the attribute taglib ["+textTagLib+"]"); 148 } 149 150 /** 151 * @param fileTagLib 152 * @return 153 * @throws EvaluatorException 154 */ 155 private TagLib _executeTLD(Config config, Resource fileTagLib,String nameSpace,String nameSpaceSeparator, CFMLString cfml) throws TemplateException { 156 // change extesnion 157 String ext=ResourceUtil.getExtension(fileTagLib,null); 158 if("jar".equalsIgnoreCase(ext)) { 159 // check anchestor file 160 Resource newFileTagLib = ResourceUtil.changeExtension(fileTagLib,"tld"); 161 if(newFileTagLib.exists())fileTagLib=newFileTagLib; 162 // check inside jar 163 else { 164 Resource tmp = getTLDFromJarAsFile(config,fileTagLib); 165 if(tmp!=null)fileTagLib=tmp; 166 } 167 } 168 169 try { 170 171 TagLib taglib = TagLibFactory.loadFromFile(fileTagLib); 172 taglib.setNameSpace(nameSpace); 173 taglib.setNameSpaceSeperator(nameSpaceSeparator); 174 return taglib; 175 } 176 catch (TagLibException e) { 177 178 throw new TemplateException(cfml,e.getMessage()); 179 } 180 } 181 182 private Resource getTLDFromJarAsFile(Config config, Resource jarFile) { 183 Resource jspTagLibDir = config.getTempDirectory().getRealResource("jsp-taglib"); 184 if(!jspTagLibDir.exists())jspTagLibDir.mkdirs(); 185 186 String filename=null; 187 try { 188 filename=Md5.getDigestAsString(ResourceUtil.getCanonicalPathEL(jarFile)+jarFile.lastModified()); 189 } catch (IOException e) {} 190 191 Resource tldFile = jspTagLibDir.getRealResource(filename+".tld"); 192 if(!tldFile.exists()) tldFile = jspTagLibDir.getRealResource(filename+".tldx"); 193 if(tldFile.exists()) return tldFile; 194 195 196 byte[] barr = getTLDFromJarAsBarr(config,jarFile); 197 if(barr==null)return null; 198 199 try { 200 IOUtil.copy(new ByteArrayInputStream(barr), tldFile,true); 201 } 202 catch (IOException e) {} 203 return tldFile; 204 } 205 206 207 private byte[] getTLDFromJarAsBarr(Config c,Resource jarFile) { 208 ZipInputStream zis = null; 209 try { 210 zis = new ZipInputStream(IOUtil.toBufferedInputStream(jarFile.getInputStream())); 211 212 byte[] buffer = new byte[0xffff]; 213 int bytes_read; 214 215 ZipEntry ze; 216 byte[] barr; 217 while((ze = zis.getNextEntry()) != null) { 218 if (!ze.isDirectory() && StringUtil.endsWithIgnoreCase(ze.getName(),".tld")) { 219 SystemOut.printDate(c.getOutWriter(),"found tld in file ["+jarFile+"] at position "+ze.getName()); 220 ByteArrayOutputStream baos=new ByteArrayOutputStream(); 221 while((bytes_read = zis.read(buffer)) != -1) 222 baos.write(buffer, 0, bytes_read); 223 //String name = ze.getName().replace('\\', '/'); 224 barr=baos.toByteArray(); 225 zis.closeEntry(); 226 baos.close(); 227 return barr; 228 } 229 } 230 } 231 catch (IOException ioe) {} 232 finally { 233 Util.closeEL(zis); 234 } 235 return null; 236 } 237 238 239 /** 240 * @param textTagLib 241 * @param nameSpace 242 * @return 243 */ 244 private TagLib _executeCTD(String textTagLib, String nameSpace, String nameSpaceSeparator) { 245 return new CustomTagLib(textTagLib,nameSpace,nameSpaceSeparator); 246 } 247 248}