001    package railo.commons.lang;
002    
003    import java.io.ByteArrayOutputStream;
004    import java.io.IOException;
005    import java.io.InputStream;
006    import java.net.URL;
007    
008    import railo.commons.io.IOUtil;
009    import railo.commons.io.SystemUtil;
010    import railo.commons.io.res.Resource;
011    import railo.commons.io.res.util.ResourceClassLoader;
012    import railo.runtime.type.Sizeable;
013    
014    /**
015     * Directory ClassLoader
016     */
017    public final class PCLBlock extends ExtendableClassLoader implements Sizeable  {
018        
019        private Resource directory;
020        private ClassLoader pcl;
021            private int size=0;
022            private int count;
023            
024    
025        /**
026         * Constructor of the class
027         * @param directory
028         * @param parent
029         * @throws IOException
030         */
031        public PCLBlock(Resource directory, ClassLoader parent) {
032            super(parent);
033            this.pcl=parent;
034            this.directory=directory;
035        }
036        
037        /**
038         * Loads the class with the specified name. This method searches for 
039         * classes in the same manner as the {@link #loadClass(String, boolean)} 
040         * method. It is called by the Java virtual machine to resolve class 
041         * references. Calling this method is equivalent to calling 
042         * <code>loadClass(name, false)</code>.
043         *
044         * @param     name the name of the class
045         * @return    the resulting <code>Class</code> object
046         * @exception ClassNotFoundException if the class was not found
047         */
048       public Class<?> loadClass(String name) throws ClassNotFoundException   {
049               return loadClass(name, false);
050       }//15075171
051    
052        /**
053         * Loads the class with the specified name.  The default implementation of
054         * this method searches for classes in the following order:<p>
055         *
056         * <ol>
057         * <li> Call {@link #findLoadedClass(String)} to check if the class has
058         *      already been loaded. <p>
059         * <li> Call the <code>loadClass</code> method on the parent class
060         *      loader.  If the parent is <code>null</code> the class loader
061         *      built-in to the virtual machine is used, instead. <p>
062         * <li> Call the {@link #findClass(String)} method to find the class. <p>
063         * </ol>
064         *
065         * If the class was found using the above steps, and the
066         * <code>resolve</code> flag is true, this method will then call the
067         * {@link #resolveClass(Class)} method on the resulting class object.
068         * <p>
069         * From the Java 2 SDK, v1.2, subclasses of ClassLoader are 
070         * encouraged to override
071         * {@link #findClass(String)}, rather than this method.<p>
072         *
073         * @param     name the name of the class
074         * @param     resolve if <code>true</code> then resolve the class
075         * @return   the resulting <code>Class</code> object
076         * @exception ClassNotFoundException if the class could not be found
077         */
078        protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
079            //if(!name.endsWith("$cf")) return super.loadClass(name, resolve); this break Webervices
080            // First, check if the class has already been loaded
081            Class<?> c = findLoadedClass(name);
082            //print.o("load:"+name+" -> "+c);
083            if (c == null) {
084                try {
085                    c =pcl.loadClass(name);//if(name.indexOf("sub")!=-1)print.ds(name);
086                } 
087                catch (Throwable t) {
088                    c = findClass(name);
089                }
090            }
091            if (resolve) {
092                resolveClass(c);
093            }
094            return c;
095       }
096        
097        
098    
099        
100        public static long lastModified(Resource res, long defaultValue)  {
101            InputStream in = null;
102            try{
103                    in=res.getInputStream();
104                    byte[] buffer = new byte[10];
105                    in.read(buffer);
106                    if(!ClassUtil.hasCF33Prefix(buffer)) return defaultValue;
107                    
108                     byte[] _buffer = new byte[]{
109                                     buffer[2],
110                                     buffer[3],
111                                     buffer[4],
112                                     buffer[5],
113                                     buffer[6],
114                                     buffer[7],
115                                     buffer[8],
116                                     buffer[9],
117                     };
118                    
119                    
120                    return NumberUtil.byteArrayToLong(_buffer);
121            }
122            catch(IOException ioe){
123                    return defaultValue;
124            }
125            finally {
126                    IOUtil.closeEL(in);
127            }
128            
129        }
130        
131        @Override
132        protected Class<?> findClass(String name) throws ClassNotFoundException {//if(name.indexOf("sub")!=-1)print.ds(name);
133            //if(!name.endsWith("$cf")) return super.findClass(name); this break Webervices
134            //File f = getFile(name.replace('.',File.separatorChar).concat(".class"));
135            //print.e("directory:"+directory+"->"+name);
136            Resource res=directory
137            .getRealResource(
138                            name.replace('.','/')
139                            .concat(".class"));
140            //File f = new File(directory,name.replace('.',File.separatorChar).concat(".class"));
141            //if(f==null) throw new ClassNotFoundException("class "+name+" not found");
142            
143            ByteArrayOutputStream baos = new ByteArrayOutputStream();
144            try {
145                IOUtil.copy(res,baos,false);
146            } 
147            catch (IOException e) {
148                    throw new ClassNotFoundException("class "+name+" is invalid or doesn't exist");
149            }
150            
151            byte[] barr=baos.toByteArray();
152            size+=barr.length;
153            count++;
154            //print.o(name+":"+count+" -> "+(size/1024));
155            IOUtil.closeEL(baos);
156            return loadClass(name, barr);
157            //return defineClass(name,barr,0,barr.length);
158        }
159        
160    
161        public Class<?> loadClass(String name, byte[] barr)   {
162            int start=0;
163            //if(ClassUtil.hasCF33Prefix(barr)) start=10;
164            size+=barr.length-start;
165            count++;
166            try {
167                    return defineClass(name,barr,start,barr.length-start);
168                    } 
169            catch (Throwable t) {
170                            SystemUtil.sleep(1);
171                            try {
172                            return defineClass(name,barr,start,barr.length-start);
173                            } 
174                            catch (Throwable t2) {
175                                    SystemUtil.sleep(1);
176                                    return defineClass(name,barr,start,barr.length-start);
177                            }
178                    }
179            //return loadClass(name,false);
180        }
181        
182        @Override
183        public URL getResource(String name) {
184            /*URL url=super.getResource(name);
185            if(url!=null) return url;
186            
187            Resource f =_getResource(name);
188            if(f!=null) {
189                try {
190                    return f.toURL();
191                } 
192                catch (MalformedURLException e) {}
193            }*/
194            return null;
195        }
196    
197        @Override
198        public InputStream getResourceAsStream(String name) {
199            InputStream is = super.getResourceAsStream(name);
200            if(is!=null) return is;
201            
202            Resource f = _getResource(name);
203            if(f!=null)  {
204                try {
205                    return IOUtil.toBufferedInputStream(f.getInputStream());
206                } 
207                catch (IOException e) {}
208            }
209            return null;
210        }
211    
212        /**
213         * returns matching File Object or null if file not exust
214         * @param name
215         * @return matching file
216         */
217        public Resource _getResource(String name) {
218            Resource f = directory.getRealResource(name);
219            if(f!=null && f.exists() && f.isFile()) return f;
220            return null;
221        }
222    
223        public boolean hasClass(String className) {
224            return hasResource(className.replace('.','/').concat(".class"));
225        }
226        
227        public boolean isClassLoaded(String className) {
228            //print.o("isClassLoaded:"+className+"-"+(findLoadedClass(className)!=null));
229            return findLoadedClass(className)!=null;
230        }
231    
232        public boolean hasResource(String name) {
233            return _getResource(name)!=null;
234        }
235    
236            /**
237             * @return the directory
238             */
239            public Resource getDirectory() {
240                    return directory;
241            }
242    
243            @Override
244            public long sizeOf() {
245                    return 0;
246            }
247            
248            public int count() {
249                    return count;
250            }
251    
252    }