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