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.runtime.type.Sizeable; 012 013 /** 014 * Directory ClassLoader 015 */ 016 public final class PhysicalClassLoader extends ClassLoader implements Sizeable { 017 018 private Resource directory; 019 private ClassLoader pcl; 020 private int size=0; 021 private int count; 022 023 /** 024 * Constructor of the class 025 * @param directory 026 * @param parent 027 * @throws IOException 028 */ 029 public PhysicalClassLoader(Resource directory, ClassLoader parent) throws IOException { 030 super(parent); 031 this.pcl=parent; 032 if(!directory.isDirectory()) 033 throw new IOException("resource "+directory+" is not a directory"); 034 if(!directory.canRead()) 035 throw new IOException("no access to "+directory+" directory"); 036 this.directory=directory; 037 } 038 039 /** 040 * Loads the class with the specified name. This method searches for 041 * classes in the same manner as the {@link #loadClass(String, boolean)} 042 * method. It is called by the Java virtual machine to resolve class 043 * references. Calling this method is equivalent to calling 044 * <code>loadClass(name, false)</code>. 045 * 046 * @param name the name of the class 047 * @return the resulting <code>Class</code> object 048 * @exception ClassNotFoundException if the class was not found 049 */ 050 public Class<?> loadClass(String name) throws ClassNotFoundException { 051 return loadClass(name, false); 052 }//15075171 053 054 /** 055 * Loads the class with the specified name. The default implementation of 056 * this method searches for classes in the following order:<p> 057 * 058 * <ol> 059 * <li> Call {@link #findLoadedClass(String)} to check if the class has 060 * already been loaded. <p> 061 * <li> Call the <code>loadClass</code> method on the parent class 062 * loader. If the parent is <code>null</code> the class loader 063 * built-in to the virtual machine is used, instead. <p> 064 * <li> Call the {@link #findClass(String)} method to find the class. <p> 065 * </ol> 066 * 067 * If the class was found using the above steps, and the 068 * <code>resolve</code> flag is true, this method will then call the 069 * {@link #resolveClass(Class)} method on the resulting class object. 070 * <p> 071 * From the Java 2 SDK, v1.2, subclasses of ClassLoader are 072 * encouraged to override 073 * {@link #findClass(String)}, rather than this method.<p> 074 * 075 * @param name the name of the class 076 * @param resolve if <code>true</code> then resolve the class 077 * @return the resulting <code>Class</code> object 078 * @exception ClassNotFoundException if the class could not be found 079 */ 080 protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 081 //if(!name.endsWith("$cf")) return super.loadClass(name, resolve); this break Webervices 082 // First, check if the class has already been loaded 083 Class<?> c = findLoadedClass(name); 084 //print.o("load:"+name+" -> "+c); 085 if (c == null) { 086 try { 087 c =pcl.loadClass(name); 088 } 089 catch (Throwable t) { 090 c = findClass(name); 091 } 092 } 093 if (resolve) { 094 resolveClass(c); 095 } 096 return c; 097 } 098 099 100 101 102 public static long lastModified(Resource res, long defaultValue) { 103 InputStream in = null; 104 try{ 105 in=res.getInputStream(); 106 byte[] buffer = new byte[10]; 107 in.read(buffer); 108 if(!ClassUtil.hasCF33Prefix(buffer)) return defaultValue; 109 110 byte[] _buffer = new byte[]{ 111 buffer[2], 112 buffer[3], 113 buffer[4], 114 buffer[5], 115 buffer[6], 116 buffer[7], 117 buffer[8], 118 buffer[9], 119 }; 120 121 122 return NumberUtil.byteArrayToLong(_buffer); 123 } 124 catch(IOException ioe){ 125 return defaultValue; 126 } 127 finally { 128 IOUtil.closeEL(in); 129 } 130 131 } 132 133 /** 134 * @see java.lang.ClassLoader#findClass(java.lang.String) 135 */ 136 protected Class<?> findClass(String name) throws ClassNotFoundException { 137 //if(!name.endsWith("$cf")) return super.findClass(name); this break Webervices 138 //File f = getFile(name.replace('.',File.separatorChar).concat(".class")); 139 Resource res=directory.getRealResource(name.replace('.','/').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 exists"); 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) throws ClassNotFoundException { 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 } catch (Throwable t2) {SystemUtil.sleep(1);} 174 } 175 return loadClass(name,false); 176 } 177 178 /** 179 * @see java.lang.ClassLoader#getResource(java.lang.String) 180 */ 181 public URL getResource(String name) { 182 /*URL url=super.getResource(name); 183 if(url!=null) return url; 184 185 Resource f =_getResource(name); 186 if(f!=null) { 187 try { 188 return f.toURL(); 189 } 190 catch (MalformedURLException e) {} 191 }*/ 192 return null; 193 } 194 195 /** 196 * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String) 197 */ 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 /** 224 * @see railo.commons.lang.ClassLoaderControl#hasClass(java.lang.String) 225 */ 226 public boolean hasClass(String className) { 227 return hasResource(className.replace('.','/').concat(".class")); 228 } 229 230 public boolean isClassLoaded(String className) { 231 //print.o("isClassLoaded:"+className+"-"+(findLoadedClass(className)!=null)); 232 return findLoadedClass(className)!=null; 233 } 234 235 /** 236 * @see railo.commons.lang.ClassLoaderControl#hasResource(java.lang.String) 237 */ 238 public boolean hasResource(String name) { 239 return _getResource(name)!=null; 240 } 241 242 /** 243 * @return the directory 244 */ 245 public Resource getDirectory() { 246 return directory; 247 } 248 249 /** 250 * @see railo.runtime.type.Sizeable#sizeOf() 251 */ 252 public long sizeOf() { 253 return 0; 254 } 255 256 public int count() { 257 return count; 258 } 259 260 }