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