1 23 24 27 28 package com.sun.jdo.api.persistence.enhancer; 29 30 import java.lang.ref.WeakReference ; 31 32 import java.io.InputStream ; 33 import java.io.ByteArrayInputStream ; 34 import java.io.ByteArrayOutputStream ; 35 import java.io.IOException ; 36 import java.io.PrintWriter ; 37 38 import java.util.Properties ; 39 40 import java.net.URLClassLoader ; 41 import java.net.URL ; 42 43 import sun.misc.Resource; 44 import sun.misc.URLClassPath; 45 46 import java.util.jar.Manifest ; 47 import java.util.jar.Attributes ; 48 import java.util.jar.Attributes.Name; 49 50 import java.security.AccessController ; 51 import java.security.AccessControlContext ; 52 import java.security.CodeSource ; 53 import java.security.PrivilegedExceptionAction ; 54 import java.security.PrivilegedActionException ; 55 import java.security.cert.Certificate ; 56 57 import com.sun.jdo.api.persistence.model.Model; 58 59 import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData; 60 import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataPropertyImpl; 61 import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataModelImpl; 62 import com.sun.jdo.api.persistence.enhancer.meta.JDOMetaDataTimer; 63 64 import com.sun.jdo.api.persistence.enhancer.util.Support; 65 66 67 69 70 76 public class EnhancerClassLoader extends URLClassLoader { 77 78 static public final String DO_SIMPLE_TIMING 79 = FilterEnhancer.DO_SIMPLE_TIMING; 80 static public final String VERBOSE_LEVEL 81 = FilterEnhancer.VERBOSE_LEVEL; 82 static public final String VERBOSE_LEVEL_QUIET 83 = FilterEnhancer.VERBOSE_LEVEL_QUIET; 84 static public final String VERBOSE_LEVEL_WARN 85 = FilterEnhancer.VERBOSE_LEVEL_WARN; 86 static public final String VERBOSE_LEVEL_VERBOSE 87 = FilterEnhancer.VERBOSE_LEVEL_VERBOSE; 88 static public final String VERBOSE_LEVEL_DEBUG 89 = FilterEnhancer.VERBOSE_LEVEL_DEBUG; 90 91 static public URL [] pathToURLs(String classpath) { 92 return URLClassPath.pathToURLs(classpath); 93 } 94 95 private boolean debug = true; 98 private boolean doTiming = false; 99 private PrintWriter out = new PrintWriter (System.out, true); 100 101 private ByteCodeEnhancer enhancer; 102 private JDOMetaData metaData; 103 private Properties settings; 104 private WeakReference outByteCodeRef; 105 106 private final URLClassPath ucp; 108 109 private final AccessControlContext acc; 111 112 private final void message() { 114 if (debug) { 115 out.println(); 116 } 117 } 118 119 private final void message(String s) { 121 if (debug) { 122 out.println(s); 123 } 124 } 125 126 private final void message(Exception e) { 128 if (debug) { 129 final String msg = ("Exception caught: " + e); out.println(msg); 131 e.printStackTrace(out); 132 } 133 } 134 135 140 protected EnhancerClassLoader(URL [] urls) { 141 super(urls); 142 acc = AccessController.getContext(); 143 ucp = new URLClassPath(urls); 144 checkUCP(urls); 145 } 146 147 152 protected EnhancerClassLoader(URL [] urls, 153 ClassLoader loader) { 154 super(urls, loader); 155 acc = AccessController.getContext(); 156 ucp = new URLClassPath(urls); 157 checkUCP(urls); 158 } 159 160 165 public EnhancerClassLoader(String classpath, 166 Properties settings, 167 PrintWriter out) { 168 this(pathToURLs(classpath)); 169 JDOMetaData metaData = new JDOMetaDataModelImpl(Model.ENHANCER, out); 170 init(metaData, settings, out); 171 } 172 173 178 public EnhancerClassLoader(URL [] urls, 179 Properties settings, 180 PrintWriter out) { 181 this(urls); 182 JDOMetaData metaData = new JDOMetaDataModelImpl(Model.ENHANCER, out); 183 init(metaData, settings, out); 184 } 185 186 191 public EnhancerClassLoader(String classpath, 192 JDOMetaData metaData, 193 Properties settings, 194 PrintWriter out) { 195 this(pathToURLs(classpath)); 196 init(metaData, settings, out); 197 } 198 199 204 public EnhancerClassLoader(URL [] urls, 205 JDOMetaData metaData, 206 Properties settings, 207 PrintWriter out) { 208 this(urls); 209 init(metaData, settings, out); 210 } 211 212 217 228 229 234 247 248 253 267 268 312 313 319 protected void addURL(URL url) { 320 throw new UnsupportedOperationException ("Not implemented yet: EnhancerClassLoader.addURL(URL)"); } 324 325 private void checkUCP(URL [] urls) { 326 if (null == urls) { 328 throw new IllegalArgumentException ("urls == null"); } 330 if (urls.length == 0) { 331 throw new IllegalArgumentException ("urls.length == 0"); } 333 334 for (int i = 0; i < urls.length; i++) { 335 super.addURL(urls[i]); 336 } 337 } 338 339 342 private void init(JDOMetaData metaData, 343 Properties settings, 344 PrintWriter out) { 345 this.out = out; 346 final String verboseLevel 347 = (settings == null ? null 348 : settings.getProperty(FilterEnhancer.VERBOSE_LEVEL)); 349 this.debug = FilterEnhancer.VERBOSE_LEVEL_DEBUG.equals(verboseLevel); 350 this.settings = settings; 351 this.metaData = metaData; 352 this.enhancer = null; 353 354 if (settings != null) { 355 final String timing 356 = settings.getProperty(FilterEnhancer.DO_SIMPLE_TIMING); 357 this.doTiming = Boolean.valueOf(timing).booleanValue(); 358 } 359 if (this.doTiming) { 360 this.metaData = new JDOMetaDataTimer(metaData); 362 } 363 364 message("EnhancerClassLoader: UCP = {"); final URL [] urls = getURLs(); 366 for (int i = 0; i < urls.length; i++) { 367 message(" " + urls[i]); } 369 message("}"); 371 message("EnhancerClassLoader: jdoMetaData = " + metaData); } 373 374 public synchronized Class loadClass(String name, boolean resolve) 375 throws ClassNotFoundException { 376 message(); 377 message("EnhancerClassLoader: loading class: " + name); 379 try { 380 Class c = null; 381 382 final String classPath = name.replace('.', '/'); 383 if (classPath.startsWith("java/") || classPath.startsWith("javax/sql/") || classPath.startsWith("javax/transaction/") || classPath.startsWith("com/sun/jdo/")) { message("EnhancerClassLoader: bootstrap class, using parent loader for class: " + name); return super.loadClass(name, resolve); 418 419 455 } 456 457 if (c == null) { 459 c = findLoadedClass(name); 460 if (c != null) { 461 message("EnhancerClassLoader: class already loaded: " + name); } 463 } 464 465 if (c == null) { 466 c = findAndEnhanceClass(name); 467 } 468 469 if (c == null) { 472 message("EnhancerClassLoader: class not found, using parent loader for class: " + name); return super.loadClass(name, resolve); 474 } 475 476 message(); 477 message("EnhancerClassLoader: loaded class: " + name); if (resolve) { 479 resolveClass(c); 480 } 481 482 message(); 483 message("EnhancerClassLoader: loaded+resolved class: " + name); return c; 485 } catch (RuntimeException e) { 486 message(); 488 message("EnhancerClassLoader: EXCEPTION SEEN: " + e); throw e; 491 } catch (ClassNotFoundException e) { 492 message(); 494 message("EnhancerClassLoader: EXCEPTION SEEN: " + e); throw e; 497 } 498 } 499 500 509 private Class findAndEnhanceClass(final String name) 510 throws ClassNotFoundException 511 { 512 try { 513 if (doTiming) { 514 Support.timer.push("EnhancerClassLoader.findAndEnhanceClass(String)", "EnhancerClassLoader.findAndEnhanceClass(" + name + ")"); } 517 return (Class ) 518 AccessController.doPrivileged(new PrivilegedExceptionAction () { 519 public Object run() throws ClassNotFoundException { 520 String path = name.replace('.', '/').concat(".class"); Resource res = ucp.getResource(path, false); 523 if (res != null) { 524 try { 525 return defineClass(name, res); 526 } catch (IOException e) { 527 final String msg 528 = ("Exception caught while loading class '" + name + "' : " + e); throw new ClassNotFoundException (msg, e); 531 } 532 } else { 533 return null; 536 } 537 } 538 }, acc); 539 } catch (PrivilegedActionException pae) { 540 throw (ClassNotFoundException ) pae.getException(); 541 } finally { 542 if (doTiming) { 543 Support.timer.pop(); 544 } 545 } 546 } 547 548 553 private Class defineClass(String name, Resource res) 554 throws IOException , ClassNotFoundException { 555 int i = name.lastIndexOf('.'); 556 URL url = res.getCodeSourceURL(); 557 if (i != -1) { 558 String pkgname = name.substring(0, i); 559 Package pkg = getPackage(pkgname); 561 Manifest man = res.getManifest(); 562 if (pkg != null) { 563 boolean ok; 565 if (pkg.isSealed()) { 566 ok = pkg.isSealed(url); 568 } else { 569 ok = (man == null) || !isSealed(pkgname, man); 572 } 573 if (!ok) { 574 throw new SecurityException ("sealing violation"); } 576 } else { 577 if (man != null) { 578 definePackage(pkgname, man, url); 579 } else { 580 definePackage(pkgname, null, null, null, null, null, null, null); 581 } 582 } 583 } 584 byte[] b = res.getBytes(); 586 Certificate [] certs = res.getCertificates(); 587 CodeSource cs = new CodeSource (url, certs); 588 589 final String classPath = name.replace('.', '/'); 592 if (!metaData.isTransientClass(classPath)) { 593 b = enhance(name, b, 0, b.length); 595 } 596 597 return defineClass(name, b, 0, b.length, cs); 598 } 599 600 private byte[] enhance(String name, byte[] data, int off, int len) 601 throws ClassNotFoundException { 602 604 final byte[] result; 605 try { 606 if (null == enhancer) { 608 enhancer = new FilterEnhancer(metaData, settings, out, null); 609 if (doTiming) { 610 enhancer = new ByteCodeEnhancerTimer(enhancer); 612 } 613 } 614 615 ByteArrayInputStream inByteCode 617 = new ByteArrayInputStream (data, off, len); 618 ByteArrayOutputStream outByteCode 619 = ((null == outByteCodeRef) 620 ? null : (ByteArrayOutputStream )outByteCodeRef.get()); 621 if (null == outByteCode) { 622 outByteCode = new ByteArrayOutputStream (10000); 623 outByteCodeRef = new WeakReference (outByteCode); 624 } 625 outByteCode.reset(); 626 627 boolean changed 629 = enhancer.enhanceClassFile(inByteCode, outByteCode); 630 631 result = (changed ? outByteCode.toByteArray() : data); 633 } catch (EnhancerUserException e) { 634 message(e); 636 final String msg = ("Exception caught while loading class '" + name + "' : " + e); throw new ClassNotFoundException (msg, e); 639 } catch(EnhancerFatalError e) { 640 message(e); 642 final String msg = ("Exception caught while loading class '" + name + "' : " + e); enhancer = null; 646 throw new ClassNotFoundException (msg, e); 647 } 648 return result; 649 } 650 651 655 private boolean isSealed(String name, Manifest man) { 656 String path = name.replace('.', '/').concat("/"); Attributes attr = man.getAttributes(path); 658 String sealed = null; 659 if (attr != null) { 660 sealed = attr.getValue(Name.SEALED); 661 } 662 if (sealed == null) { 663 if ((attr = man.getMainAttributes()) != null) { 664 sealed = attr.getValue(Name.SEALED); 665 } 666 } 667 return "true".equalsIgnoreCase(sealed); } 669 } 670 | Popular Tags |