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.net; 020 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.PrintWriter; 024import java.net.MalformedURLException; 025import java.net.URL; 026import java.util.ArrayList; 027import java.util.List; 028 029import lucee.commons.io.IOUtil; 030import lucee.commons.io.SystemUtil; 031import lucee.commons.io.res.Resource; 032import lucee.commons.io.res.util.ResourceClassLoader; 033import lucee.commons.io.res.util.ResourceUtil; 034import lucee.commons.lang.SystemOut; 035import lucee.loader.TP; 036import lucee.loader.engine.CFMLEngineFactory; 037import lucee.runtime.Info; 038import lucee.runtime.config.Config; 039import lucee.runtime.config.ConfigWeb; 040 041public class JarLoader { 042 043 public static final short WHEN_EXISTS_UPDATE=1; 044 public static final short WHEN_EXISTS_RETURN_JAR=2; 045 public static final short WHEN_EXISTS_THROW_EXP=4; 046 public static final short WHEN_EXISTS_RETURN_NULL=8; 047 048 049 050 051 /** 052 * this loads the given jars from update provider, copy it to lib directory (where lucee.jar is located) and load them to a ClassLoader 053 * @param pc 054 * @param jars jars names to Load 055 * @return Classloader with loaded jars for temporary use, after restart the engine this jars are loaded by the servlet engine 056 * @throws IOException 057 */ 058 public static ClassLoader loadJars(Config config, String[] jars,ClassLoader parent) throws IOException { 059 return new ResourceClassLoader(download(config, jars),parent); 060 } 061 062 063 public static Resource[] download(Config config, String[] jars) throws IOException { 064 List<Resource> list=new ArrayList<Resource>(); 065 Resource jar; 066 lastCheck=-1; 067 for(int i=0;i<jars.length;i++){ 068 jar=download(config, jars[i], WHEN_EXISTS_UPDATE); 069 if(jar!=null) list.add(jar); 070 } 071 return list.toArray(new Resource[list.size()]); 072 } 073 074 075 private static Resource download(Config config,String jarName, short whenExists) throws IOException { 076 // some variables nned later 077 PrintWriter out = config.getOutWriter(); 078 079 URL dataUrl=toURL(config,jarName); 080 081 // destination file 082 ClassLoader mainClassLoader = new TP().getClass().getClassLoader(); 083 084 Resource lib = config.getResource(CFMLEngineFactory.getClassLoaderRoot(mainClassLoader).getCanonicalPath()); 085 086 Resource jar=lib.getRealResource(jarName); 087 SystemOut.printDate(out,"Check for jar at "+dataUrl); 088 if(jar.exists()){ 089 if(whenExists==WHEN_EXISTS_RETURN_JAR) return jar; 090 else if(whenExists==WHEN_EXISTS_RETURN_NULL) return null; 091 else if(whenExists==WHEN_EXISTS_UPDATE) { 092 // compare local and remote 093 long localLen=jar.length(); 094 long remoteLengh=HTTPUtil.length(dataUrl); 095 // only update when size change more than 10 096 if(localLen==remoteLengh){ 097 SystemOut.printDate(out,"jar "+jar+" is up to date"); 098 return jar; 099 } 100 //if(!jar.delete()) throw new IOException("cannot update jar ["+jar+"], jar is locked or write protected, stop the servlet engine and delete this jar manually."); 101 } 102 else throw new IOException("jar ["+jar+"] exists already"); 103 } 104 105 Resource tmp = SystemUtil.getTempFile(".jar", false); 106 try { 107 //long len=HTTPUtil.length(); 108 InputStream is = (InputStream)dataUrl.getContent(); 109 // copy input stream to lib directory 110 IOUtil.copy(is, tmp,true); 111 jar.delete(); 112 tmp.moveTo(jar); 113 } 114 finally{ 115 tmp.delete(); 116 } 117 SystemOut.printDate(out,"created/updated jar "+jar); 118 119 return jar; 120 } 121 122 private static URL toURL(Config config, String jarName) throws MalformedURLException { 123 URL hostUrl=config.getUpdateLocation(); 124 if(hostUrl==null)hostUrl=new URL("http://stable.lucee.org"); 125 return new URL(hostUrl,"/lucee/remote/jars/"+(Info.getMajorVersion()+"."+Info.getMinorVersion())+"/"+jarName); 126 } 127 128 129 public static boolean exists(ConfigWeb config,String[] jarNames) { 130 for(int i=0;i<jarNames.length;i++){ 131 if(!exists(config, jarNames[i])) return false; 132 } 133 return true; 134 } 135 136 /** 137 * check if one of given jar has changed or not exist 138 * @param config 139 * @param jarNames 140 * @return 141 */ 142 private static boolean changed=false; 143 private static long lastCheck=-1; 144 public static boolean changed(ConfigWeb config,String[] jarNames) { 145 if((lastCheck+300000)<System.currentTimeMillis()) { 146 changed=false; 147 for(int i=0;i<jarNames.length;i++){ 148 if(changed(config, jarNames[i])) { 149 changed=true; 150 break; 151 } 152 } 153 lastCheck=System.currentTimeMillis(); 154 } 155 return changed; 156 } 157 158 private static boolean exists(ConfigWeb config,String jarName) { 159 Resource res = _toResource(config, jarName); 160 if(res==null) return false; 161 return res.exists(); 162 } 163 164 private static boolean changed(ConfigWeb config,String jarName) { 165 Resource res = _toResource(config, jarName); 166 if(res==null) { 167 return true; 168 } 169 170 try { 171 URL dataUrl = toURL(config,jarName); 172 boolean changed=res.length()!=HTTPUtil.length(dataUrl); 173 174 return changed; 175 } catch (IOException e) { 176 return false; 177 } 178 } 179 180 private static Resource _toResource(ConfigWeb config,String jarName) { 181 // destination file 182 ClassLoader mainClassLoader = new TP().getClass().getClassLoader(); 183 try { 184 Resource lib = ResourceUtil.toResourceNotExisting(config,CFMLEngineFactory.getClassLoaderRoot(mainClassLoader).getCanonicalPath()); 185 return lib.getRealResource(jarName); 186 } catch (IOException e) { 187 return null; 188 } 189 } 190}