1 19 20 package org.objectweb.jac.core; 21 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InvalidClassException ; 28 import java.io.ObjectInputStream ; 29 import java.io.ObjectOutputStream ; 30 import java.lang.reflect.Field ; 31 import java.lang.reflect.Method ; 32 import java.net.URL ; 33 import java.net.URLClassLoader ; 34 import java.security.MessageDigest ; 35 import java.security.NoSuchAlgorithmException ; 36 import java.util.Arrays ; 37 import java.util.HashSet ; 38 import java.util.Hashtable ; 39 import java.util.Iterator ; 40 import java.util.Properties ; 41 import org.apache.log4j.Logger; 42 import org.objectweb.jac.core.rtti.ClassInfo; 43 import org.objectweb.jac.core.rtti.LoadtimeRTTI; 44 import org.objectweb.jac.util.ExtArrays; 45 import org.objectweb.jac.util.Streams; 46 import org.objectweb.jac.util.Strings; 47 48 61 public class JacLoader extends ClassLoader { 62 static Logger logger = Logger.getLogger("loader"); 63 static Logger loggerRes = Logger.getLogger("loader.resource"); 64 65 70 private Hashtable classes = new Hashtable (); 71 72 73 private boolean write = false; 74 75 76 private boolean clean = false; 77 78 private ClassLoader parentLoader = ClassLoader.getSystemClassLoader(); 79 80 private WrappeeTranslator wt = null; 81 private String bytecodeModifier; 82 83 84 private String [] ignoredPackages = { 85 "java.", "javax.", "sun.", "org.xml.sax.", "org.w3c.dom.", "org.apache.log4j" 86 }; 87 88 90 private HashSet ignoredClasses = new HashSet (); 91 92 93 private static ClassLoader otherClassLoader; 94 95 LoadtimeRTTI rtti; 96 97 106 public JacLoader(boolean write, 107 boolean clean, 108 ClassLoader otherClassLoader) 109 throws Exception 110 { 111 logger.info("building JacLoader..."); 112 this.write = write; 114 this.clean = clean; 115 if (otherClassLoader != null) 116 JacLoader.otherClassLoader = otherClassLoader; 117 118 ignoredClasses.add("org.objectweb.jac.util.Log"); 119 ignoredClasses.add("org.objectweb.jac.core.Jac"); 120 ignoredClasses.add("org.objectweb.jac.core.rtti.LoadtimeRTTI"); 121 ignoredClasses.add("org.objectweb.jac.core.rtti.ClassInfo"); 122 ignoredClasses.add("org.objectweb.jac.core.rtti.MethodInfo"); 123 ignoredClasses.add("org.objectweb.jac.core.rtti.InvokeInfo"); 124 JacPropLoader.loadProps(); 126 logger.info("JacPropLoader = "+ 127 Strings.hex(JacPropLoader.class)); 128 129 bytecodeModifier = org.objectweb.jac.core.JacPropLoader.bytecodeModifier; 131 logger.info("jacloader: Selected bytecode modifier = '" + 132 bytecodeModifier +"'"); 133 134 Class c = Class.forName("org.objectweb.jac.core.translators.WrappeeTranslator_"+ 136 bytecodeModifier); 137 Class repositoryClass = loadClass("org.objectweb.jac.core.rtti.ClassRepository",true); 138 rtti = (LoadtimeRTTI) 139 repositoryClass.getMethod("get",ExtArrays.emptyClassArray).invoke(null,ExtArrays.emptyObjectArray); 140 wt = (WrappeeTranslator)c.getConstructor( 141 new Class [] {LoadtimeRTTI.class}).newInstance( 142 new Object [] {rtti}); 143 144 logger.info("Instanciated bytecode modifier is "+wt); 145 } 146 147 148 155 public JacLoader(boolean write, 156 boolean clean) 157 throws Exception 158 { 159 this(write, clean, null); 160 } 161 162 163 public void setWrappeeTranslator(WrappeeTranslator wt) { 164 this.wt = wt; 165 } 166 167 private void addIgnoredPkgs(String [] ignoredPackages) { 168 String [] new_p = new String [ignoredPackages.length + 169 this.ignoredPackages.length]; 170 171 System.arraycopy(this.ignoredPackages, 0, new_p, 0, 172 this.ignoredPackages.length); 173 System.arraycopy(ignoredPackages, 0, new_p, this.ignoredPackages.length, 174 ignoredPackages.length); 175 this.ignoredPackages = new_p; 176 } 177 178 183 public boolean deferClass(String classname) { 184 if (ignoredClasses.contains(classname)) 185 return true; 186 for(int i=0; i<ignoredPackages.length; i++) { 187 if (classname.startsWith(ignoredPackages[i])) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 198 protected boolean analyzeClass(String classname) { 199 return false; 200 } 201 202 protected Class loadClass(String class_name, boolean resolve) 203 throws ClassNotFoundException 204 { 205 logger.debug("loadClass("+class_name+","+resolve+")"); 206 Class cl = null; 207 208 cl = findLoadedClass(class_name); 209 if (cl!=null) { 210 logger.debug("already loaded "+class_name); 211 return cl; 212 } 213 cl = (Class )classes.get(class_name); 214 if (cl==null) { 215 if (deferClass(class_name) && !JacPropLoader.adaptClass(class_name)) { 216 logger.debug("defer "+class_name); 217 byte[] bytes = null; 218 if (analyzeClass(class_name)) { 219 try { 220 logger.debug("fill RTTI for "+class_name); 221 bytes = wt.fillClassRTTI(class_name); 222 } catch (Exception e) { 223 logger.error("Failed to fill RTTI for "+class_name,e); 224 throw new ClassNotFoundException ( 226 "jacloader: cannot find class "+ 227 class_name+" on disk: "+e); 228 } 229 } 230 cl = parentLoader.loadClass(class_name); 231 } 232 233 if (cl == null) { 234 byte[] bytes; 235 String resourcePath = "/" + class_name.replace('.', '/') + ".class"; 236 logger.debug("resourcePath = "+resourcePath); 237 bytes = loadResource(resourcePath); 238 239 if (wt!=null && classIsToBeAdapted(class_name)) { 240 logger.info("adapting "+class_name); 241 String baseName = 242 Jac.getJacRoot()+"classes_"+bytecodeModifier+"/"+ 243 class_name.replace('.','/'); 244 File cacheFile = new File (baseName+".class"); 245 MessageDigest digest; 246 boolean useCache = false; 247 File md5File = new File (baseName+".md5"); 248 File rttiFile = new File (baseName+".rtti"); 249 byte[] orig_md5 = null; 250 try { 251 digest = MessageDigest.getInstance("MD5"); 252 digest.update(bytes); 253 orig_md5 = digest.digest(); 254 if (md5File.exists()) { 255 byte[] stored_md5 = loadFile(md5File); 256 useCache = Arrays.equals(orig_md5,stored_md5); 257 } 258 } catch (NoSuchAlgorithmException e) { 259 logger.warn("Could not get an MD5 digest: "+e); 260 } 261 boolean loaded = false; 262 if (useCache && cacheFile.exists() && rttiFile.exists()) { 263 logger.info("loading class from cache "+cacheFile); 264 bytes = loadFile(cacheFile); 265 try { 266 FileInputStream rttiStream = new FileInputStream (rttiFile); 267 ObjectInputStream objStream = new ObjectInputStream (rttiStream); 268 ClassInfo classInfo = (ClassInfo)objStream.readObject(); 269 rttiStream.close(); 270 objStream.close(); 271 rtti.setClassInfo(class_name,classInfo); 272 loaded = true; 273 } catch (InvalidClassException e) { 274 logger.info("Rtti format must have changed: "+rttiFile); 276 } catch (Exception e) { 277 logger.error("Failed to read rtti cache file "+rttiFile+": "+e); 278 } 279 } 280 if (!loaded) { 281 try { 282 bytes = wt.translateClass(class_name); 284 } catch (Exception e) { 285 logger.error("Failed to translate class "+class_name,e); 286 throw new ClassNotFoundException ( 287 "jacloader: cannot find class "+ 288 class_name+" on disk: "+e); 289 } 290 if (bytes!=null && write) { 291 logger.info("writing "+cacheFile); 292 try { 293 cacheFile.getParentFile().mkdirs(); 294 FileOutputStream out = new FileOutputStream (cacheFile); 295 try { 296 out.write(bytes); 297 } finally { 298 out.close(); 299 } 300 } catch (Exception e) { 301 logger.warn("Failed to write class file "+cacheFile+": "+e); 302 } 303 if (orig_md5!=null) { 304 logger.info("writing "+md5File); 305 try { 306 md5File.getParentFile().mkdirs(); 307 FileOutputStream out = new FileOutputStream (md5File); 308 try { 309 out.write(orig_md5); 310 } finally { 311 out.close(); 312 } 313 } catch (Exception e) { 314 logger.warn("Failed to write class file "+md5File+": "+e); 315 } 316 } 317 try { 318 FileOutputStream rttiStream = new FileOutputStream (rttiFile); 319 ObjectOutputStream objStream = new ObjectOutputStream (rttiStream); 320 objStream.writeObject(rtti.getClassInfo(class_name)); 321 objStream.flush(); 322 rttiStream.close(); 323 objStream.close(); 324 } catch (Exception e) { 325 logger.error("Failed to write rtti cache file "+rttiFile+": "+e); 326 } 327 } 328 } 329 } 330 logger.debug("defineClass "+class_name); 331 if (bytes==null) { 332 logger.debug("defer "+class_name); 333 try { 334 if (otherClassLoader!=null) 335 cl = otherClassLoader.loadClass(class_name); 336 else 337 cl = parentLoader.loadClass(class_name); 338 } catch(Exception e) { 339 logger.error("Failed to load class "+class_name,e); 340 } 341 } else { 342 try { 343 cl = defineClass(class_name, bytes, 0, bytes.length); 344 } catch(Exception e1) { 345 logger.error("Failed to define class "+class_name,e1); 346 logger.debug("defer "+class_name); 348 bytes = null; 349 if (analyzeClass(class_name)) 350 try { 351 logger.debug("fill RTTI for "+class_name); 352 bytes = wt.fillClassRTTI(class_name); 353 } catch (Exception e) { 354 logger.error("Failed to fill RTTI for "+class_name,e); 355 throw new ClassNotFoundException ( 356 "jacloader: cannot find class "+ 357 class_name+" on disk: "+e); 358 } 359 cl = parentLoader.loadClass(class_name); 360 } 361 } 363 } 364 365 if (resolve) 366 resolveClass(cl); 367 } 368 369 if (cl.getClassLoader()!=null) 370 logger.info(class_name+"@"+Integer.toHexString(cl.hashCode())+ 371 " ["+cl.getClassLoader()+"]"); 372 373 logger.debug("----------"); 374 classes.put(class_name, cl); 375 376 return cl; 377 } 378 379 public InputStream getResourceAsStream(String name) 380 { 381 loggerRes.debug("getResourceAsStream: "+name); 382 383 if ((name == null) || (name.length() == 0)) 384 return null; 385 386 InputStream result = null; 387 388 result = super.getResourceAsStream(name); 389 if ((result == null) && (otherClassLoader != null)) { 390 loggerRes.debug(" resource not found with system classloader, trying with: "+otherClassLoader); 391 result = otherClassLoader.getResourceAsStream(name); 392 } 393 return result; 394 } 395 396 public URL getResource(String name) 397 { 398 loggerRes.debug("getResource: "+name+" (parent="+getParent()+")"); 399 400 URL result = null; 401 402 if (getParent() != null) { 404 result = getParent().getResource(name); 405 } 406 if (result == null) { 407 result = findResource(name); 408 } 409 410 if ((result == null) && (otherClassLoader != null)) { 412 loggerRes.debug(" resource not found with "+getParent()+", trying with: "+otherClassLoader); 413 if (otherClassLoader instanceof URLClassLoader ) 414 loggerRes.debug(" classpath="+Arrays.asList(((URLClassLoader )otherClassLoader).getURLs())); 415 result = otherClassLoader.getResource(name); 416 } 417 418 return result; 419 } 420 421 byte[] loadResource(String resourcePath) throws ClassNotFoundException { 422 InputStream in = null; 423 424 logger.debug( "loadResource: " + resourcePath); 425 426 in = super.getClass().getResourceAsStream(resourcePath); 427 428 if ((in == null) && (otherClassLoader != null)) 430 { 431 logger.debug( 432 "loadResource: searching in otherClassLoader ..."); 433 in = otherClassLoader.getResourceAsStream(resourcePath.substring(1)); 434 } 435 436 if (in == null) 437 { 438 throw new ClassNotFoundException ("jacloader: Can not find resource "+resourcePath); 439 } 440 try { 441 return Streams.readStream(in); 442 } catch (IOException e) { 443 throw new ClassNotFoundException ( 444 "jacloader: failed to load resource "+resourcePath+" : "+e); 445 } 446 447 } 448 449 byte[] loadFile(File file) throws ClassNotFoundException { 450 try { 451 InputStream in = new FileInputStream (file); 452 if (in == null) 453 throw new ClassNotFoundException ("jacloader: Can not find resource "+file); 454 return Streams.readStream(in); 455 } catch (IOException e) { 456 throw new ClassNotFoundException ( 457 "jacloader: failed to load resource "+file+" : "+e); 458 } 459 460 } 461 462 474 public static boolean classIsToBeAdapted(String name) { 475 int index = name.lastIndexOf("."); 477 String packagename = ""; 478 if (index!=-1) 479 packagename = name.substring(0,index); 480 Iterator it; 481 if (JacPropLoader.adaptClass(name)) 482 return true; 483 484 if ( name.endsWith(".Run") || 486 name.endsWith(".Main") || 487 name.endsWith("AC") || 488 name.endsWith("Wrapper") || 489 (name.indexOf('$') != -1) || 490 name.endsWith("Exception") || 491 name.startsWith("org.objectweb.jac.core") || 492 name.startsWith("org.objectweb.jac.util") || 493 name.startsWith("org.objectweb.jac.aspects")) 494 return false; 495 496 if (JacPropLoader.doNotAdaptClass(name)) 497 return false; 498 499 return true; 500 } 501 502 511 public static void displayClassInfo(String name) 512 { 513 System.out.println ("jacloader: Displaying data on class " + name); 514 Class cl = null; 515 try { 516 cl = Class.forName (name); 517 } 518 catch (Exception e) 519 { 520 System.out.println ("\tClass is not available from the loader."); 521 return; 522 } 523 Field [] fl = cl.getDeclaredFields(); 524 for (int i=0; i<fl.length; i++) 525 { 526 System.out.println ("\tField "+i+" : name("+ 527 fl[i].getName()+"), type("+ 528 fl[i].getType().getName() 529 +"), attr("+fl[i].getModifiers()+")"); 530 } 531 Method [] fm = cl.getDeclaredMethods(); 532 for (int i=0; i<fm.length; i++) 533 { 534 System.out.println ("\tMethod "+i+" ("+ 535 fm[i].getName()+"), return type is "+ 536 fm[i].getReturnType().getName()); 537 Class [] clexcep = fm[i].getExceptionTypes(); 538 for (int j=0; j<clexcep.length;j++) 539 System.out.println ("\t\tThrow Exception : "+clexcep[j].getName()); 540 Class [] clpar = fm[i].getParameterTypes(); 541 for (int j=0; j<clpar.length;j++) 542 System.out.println ("\t\tParameter number "+j+" is a "+clpar[j].getName()); 543 } 544 } 545 546 547 553 public boolean isLoaded (String classname) { 554 return (classes.containsKey(classname)); 555 } 556 557 568 569 public void run(String classname, String [] args) throws Throwable { 570 Class c = this.loadClass(classname); 571 ClassLoader saved = Thread.currentThread().getContextClassLoader(); 572 try { 573 Thread.currentThread().setContextClassLoader(this); 574 c.getDeclaredMethod("main", new Class [] { String [].class }) 575 .invoke(null, new Object [] { args }); 576 } 577 catch (java.lang.reflect.InvocationTargetException e) { 578 throw e.getTargetException(); 579 } 580 finally { 581 Thread.currentThread().setContextClassLoader(saved); 582 } 583 } 584 585 589 public void readProperties(Properties props) { 590 JacPropLoader.addProps(props); 591 } 592 593 596 public static void main(String [] args) throws Exception { 597 JacLoader loader = new JacLoader(true,true, otherClassLoader); 598 for (int i=0; i<args.length; i++) { 599 JacPropLoader.packagesToAdapt.add(args[i]); 600 loader.loadClass(args[i]); 601 } 602 } 603 } 604 | Popular Tags |