1 22 package org.jboss.mx.loading; 23 24 import java.io.ByteArrayOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.net.MalformedURLException ; 28 import java.net.URL ; 29 import java.net.URLClassLoader ; 30 import java.security.CodeSource ; 31 import java.security.PermissionCollection ; 32 import java.security.Policy ; 33 import java.security.ProtectionDomain ; 34 import java.security.cert.Certificate ; 35 import java.util.Enumeration ; 36 import java.util.HashSet ; 37 import java.util.Vector ; 38 import java.util.Collections ; 39 import java.util.Set ; 40 41 import javax.management.MalformedObjectNameException ; 42 import javax.management.ObjectName ; 43 44 import org.jboss.logging.Logger; 45 import org.jboss.util.loading.Translator; 46 import org.jboss.util.collection.SoftSet; 47 48 import EDU.oswego.cs.dl.util.concurrent.ReentrantLock; 49 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap; 50 51 57 public abstract class RepositoryClassLoader extends URLClassLoader 58 { 59 61 62 private static final Logger log = Logger.getLogger(RepositoryClassLoader.class); 63 64 65 private static final URL [] EMPTY_URL_ARRAY = {}; 66 67 69 70 protected LoaderRepository repository = null; 71 72 protected Exception unregisterTrace; 73 74 75 private int addedOrder; 76 77 78 protected ClassLoader parent = null; 79 80 81 private Set classBlackList = Collections.synchronizedSet(new SoftSet()); 82 83 private Set resourceBlackList = Collections.synchronizedSet(new HashSet ()); 84 85 private ConcurrentReaderHashMap resourceCache = new ConcurrentReaderHashMap(); 86 87 88 protected ReentrantLock loadLock = new ReentrantLock(); 89 90 91 protected int loadClassDepth; 92 93 95 97 103 protected RepositoryClassLoader(URL [] urls, ClassLoader parent) 104 { 105 super(urls, parent); 106 this.parent = parent; 107 String mode = ClassToStringAction.getProperty("org.jboss.mx.loading.blacklistMode", null); 109 if( mode == null || mode.equalsIgnoreCase("HashSet") ) 110 { 111 classBlackList = Collections.synchronizedSet(new HashSet ()); 112 resourceBlackList = Collections.synchronizedSet(new HashSet ()); 113 } 114 else if( mode.equalsIgnoreCase("SoftSet") ) 115 { 116 classBlackList = Collections.synchronizedSet(new SoftSet()); 117 resourceBlackList = Collections.synchronizedSet(new SoftSet()); 118 } 119 } 120 121 123 128 public abstract ObjectName getObjectName() throws MalformedObjectNameException ; 129 130 133 public LoaderRepository getLoaderRepository() 134 { 135 return repository; 136 } 137 138 143 public void setRepository(LoaderRepository repository) 144 { 145 log.debug("setRepository, repository="+repository+", cl=" + this); 146 this.repository = repository; 147 } 148 149 154 public int getAddedOrder() 155 { 156 return addedOrder; 157 } 158 159 164 public void setAddedOrder(int addedOrder) 165 { 166 this.addedOrder = addedOrder; 167 } 168 169 172 public Class loadClassLocally(String name, boolean resolve) 173 throws ClassNotFoundException 174 { 175 boolean trace = log.isTraceEnabled(); 176 if( trace ) 177 log.trace("loadClassLocally, " + this + " name=" + name); 178 Class result = null; 179 try 180 { 181 if (isClassBlackListed(name)) 182 { 183 if( trace ) 184 log.trace("Class in blacklist, name="+name); 185 throw new ClassNotFoundException ("Class Not Found(blacklist): " + name); 186 } 187 188 try 189 { 190 result = super.loadClass(name, resolve); 191 return result; 192 } 193 catch (ClassNotFoundException cnfe) 194 { 195 addToClassBlackList(name); 196 if( name.charAt(0) == '[' ) 198 { 199 result = Class.forName(name, true, this); 200 removeFromClassBlackList(name); 201 return result; 202 } 203 if( trace ) 204 log.trace("CFNE: Adding to blacklist: "+name); 205 throw cnfe; 206 } 207 } 208 finally 209 { 210 if (trace) 211 { 212 if (result != null) 213 log.trace("loadClassLocally, " + this + " name=" + name + " class=" + result + " cl=" + result.getClassLoader()); 214 else 215 log.trace("loadClassLocally, " + this + " name=" + name + " not found"); 216 } 217 } 218 } 219 220 223 public URL getResourceLocally(String name) 224 { 225 URL resURL = (URL ) resourceCache.get(name); 226 if (resURL != null) 227 return resURL; 228 if (isResourceBlackListed(name)) 229 return null; 230 resURL = super.getResource(name); 231 if( log.isTraceEnabled() == true ) 232 log.trace("getResourceLocally("+this+"), name="+name+", resURL:"+resURL); 233 if (resURL == null) 234 addToResourceBlackList(name); 235 else 236 resourceCache.put(name, resURL); 237 return resURL; 238 } 239 240 245 public URL getURL() 246 { 247 URL [] urls = super.getURLs(); 248 if (urls.length > 0) 249 return urls[0]; 250 else 251 return null; 252 } 253 254 public void unregister() 255 { 256 log.debug("Unregistering cl=" + this); 257 if (repository != null) 258 repository.removeClassLoader(this); 259 clearBlacklists(); 260 resourceCache.clear(); 261 repository = null; 262 this.unregisterTrace = new Exception (); 263 } 264 265 271 public URL [] getClasspath() 272 { 273 return super.getURLs(); 274 } 275 276 281 public URL [] getAllURLs() 282 { 283 return repository.getURLs(); 284 } 285 286 291 public void addToClassBlackList(String name) 292 { 293 classBlackList.add(name); 294 } 295 296 301 public void removeFromClassBlackList(String name) 302 { 303 classBlackList.remove(name); 304 } 305 306 312 public boolean isClassBlackListed(String name) 313 { 314 return classBlackList.contains(name); 315 } 316 317 320 public void clearClassBlackList() 321 { 322 classBlackList.clear(); 323 } 324 325 330 public void addToResourceBlackList(String name) 331 { 332 resourceBlackList.add(name); 333 } 334 335 340 public void removeFromResourceBlackList(String name) 341 { 342 resourceBlackList.remove(name); 343 } 344 345 351 public boolean isResourceBlackListed(String name) 352 { 353 return resourceBlackList.contains(name); 354 } 355 356 359 public void clearResourceBlackList() 360 { 361 resourceBlackList.clear(); 362 } 363 364 367 public void clearBlacklists() 368 { 369 clearClassBlackList(); 370 clearResourceBlackList(); 371 } 372 373 374 376 383 public Class loadClass(String name, boolean resolve) 384 throws ClassNotFoundException 385 { 386 boolean trace = log.isTraceEnabled(); 387 if (trace) 388 log.trace("loadClass " + this + " name=" + name+", loadClassDepth="+loadClassDepth); 389 Class clazz = null; 390 try 391 { 392 if (repository != null) 393 { 394 clazz = repository.getCachedClass(name); 395 if (clazz != null) 396 { 397 if( log.isTraceEnabled() ) 398 { 399 StringBuffer buffer = new StringBuffer ("Loaded class from cache, "); 400 ClassToStringAction.toString(clazz, buffer); 401 log.trace(buffer.toString()); 402 } 403 return clazz; 404 } 405 } 406 clazz = loadClassImpl(name, resolve, Integer.MAX_VALUE); 407 return clazz; 408 } 409 finally 410 { 411 if (trace) 412 { 413 if (clazz != null) 414 log.trace("loadClass " + this + " name=" + name + " class=" + clazz + " cl=" + clazz.getClassLoader()); 415 else 416 log.trace("loadClass " + this + " name=" + name + " not found"); 417 } 418 } 419 } 420 421 428 public Class loadClassBefore(String name) 429 throws ClassNotFoundException 430 { 431 boolean trace = log.isTraceEnabled(); 432 if (trace) 433 log.trace("loadClassBefore " + this + " name=" + name); 434 Class clazz = null; 435 try 436 { 437 clazz = loadClassImpl(name, false, addedOrder); 438 return clazz; 439 } 440 finally 441 { 442 if (trace) 443 { 444 if (clazz != null) 445 log.trace("loadClassBefore " + this + " name=" + name + " class=" + clazz + " cl=" + clazz.getClassLoader()); 446 else 447 log.trace("loadClassBefore " + this + " name=" + name + " not found"); 448 } 449 } 450 } 451 452 public abstract Class loadClassImpl(String name, boolean resolve, int stopAt) 453 throws ClassNotFoundException ; 454 455 459 public URL getResource(String name) 460 { 461 if (repository != null) 462 return repository.getResource(name, this); 463 return null; 464 } 465 466 473 public Enumeration findResources(String name) throws IOException 474 { 475 Vector resURLs = new Vector (); 476 if( repository == null ) 477 { 478 String msg = "Invalid use of destroyed classloader, UCL destroyed at:"; 479 IOException e = new IOException (msg); 480 e.initCause(this.unregisterTrace); 481 throw e; 482 } 483 repository.getResources(name, this, resURLs); 484 return resURLs.elements(); 485 } 486 487 490 public Enumeration findResourcesLocally(String name) throws IOException 491 { 492 return super.findResources(name); 493 } 494 495 502 protected Class findClass(String name) throws ClassNotFoundException 503 { 504 boolean trace = log.isTraceEnabled(); 505 if( trace ) 506 log.trace("findClass, name="+name); 507 if (isClassBlackListed(name)) 508 { 509 if( trace ) 510 log.trace("Class in blacklist, name="+name); 511 throw new ClassNotFoundException ("Class Not Found(blacklist): " + name); 512 } 513 514 Translator translator = repository.getTranslator(); 515 if (translator != null) 516 { 517 try 519 { 520 URL classUrl = getClassURL(name); 522 byte[] rawcode = loadByteCode(classUrl); 523 URL codeSourceUrl = getCodeSourceURL(name, classUrl); 524 ProtectionDomain pd = getProtectionDomain(codeSourceUrl); 525 byte[] bytecode = translator.transform(this, name, null, pd, rawcode); 526 if( bytecode == null ) 528 bytecode = rawcode; 529 definePackage(name); 531 return defineClass(name, bytecode, 0, bytecode.length, pd); 532 } 533 catch(ClassNotFoundException e) 534 { 535 throw e; 536 } 537 catch (Throwable ex) 538 { 539 throw new ClassNotFoundException (name, ex); 540 } 541 } 542 543 Class clazz = null; 544 try 545 { 546 clazz = findClassLocally(name); 547 } 548 catch(ClassNotFoundException e) 549 { 550 if( trace ) 551 log.trace("CFNE: Adding to blacklist: "+name); 552 addToClassBlackList(name); 553 throw e; 554 } 555 return clazz; 556 } 557 558 564 protected Class findClassLocally(String name) throws ClassNotFoundException 565 { 566 return super.findClass(name); 567 } 568 569 575 protected void definePackage(String className) 576 { 577 int i = className.lastIndexOf('.'); 578 if (i == -1) 579 return; 580 581 try 582 { 583 definePackage(className.substring(0, i), null, null, null, null, null, null, null); 584 } 585 catch (IllegalArgumentException alreadyDone) 586 { 587 } 588 } 589 590 593 public void addURL(URL url) 594 { 595 if( url == null ) 596 throw new IllegalArgumentException ("url cannot be null"); 597 598 if( repository.addClassLoaderURL(this, url) == true ) 599 { 600 log.debug("Added url: "+url+", to ucl: "+this); 601 String query = url.getQuery(); 603 if( query != null ) 604 { 605 String ext = url.toExternalForm(); 606 String ext2 = ext.substring(0, ext.length() - query.length() - 1); 607 try 608 { 609 url = new URL (ext2); 610 } 611 catch(MalformedURLException e) 612 { 613 log.warn("Failed to strip query from: "+url, e); 614 } 615 } 616 super.addURL(url); 617 clearBlacklists(); 618 } 619 else if( log.isTraceEnabled() ) 620 { 621 log.trace("Ignoring duplicate url: "+url+", for ucl: "+this); 622 } 623 } 624 625 633 public URL [] getURLs() 634 { 635 return EMPTY_URL_ARRAY; 636 } 637 638 public Package getPackage(String name) 639 { 640 return super.getPackage(name); 641 } 642 643 public Package [] getPackages() 644 { 645 return super.getPackages(); 646 } 647 648 650 656 public final boolean equals(Object other) 657 { 658 return super.equals(other); 659 } 660 661 667 public final int hashCode() 668 { 669 return super.hashCode(); 670 } 671 672 675 public String toString() 676 { 677 return super.toString() + "{ url=" + getURL() + " }"; 678 } 679 680 682 687 protected boolean attempt(long waitMS) 688 { 689 boolean acquired = false; 690 boolean trace = log.isTraceEnabled(); 691 boolean threadWasInterrupted = Thread.interrupted(); 693 try 694 { 695 acquired = loadLock.attempt(waitMS); 696 } 697 catch(InterruptedException e) 698 { 699 } 700 finally 701 { 702 if( threadWasInterrupted ) 704 Thread.currentThread().interrupt(); 705 } 706 if( trace ) 707 log.trace("attempt("+loadLock.holds()+") was: "+acquired+" for :"+this); 708 return acquired; 709 } 710 711 715 protected void acquire() 716 { 717 boolean threadWasInterrupted = Thread.interrupted(); 719 try 720 { 721 loadLock.acquire(); 722 } 723 catch(InterruptedException e) 724 { 725 } 726 finally 727 { 728 if( threadWasInterrupted ) 730 Thread.currentThread().interrupt(); 731 } 732 if( log.isTraceEnabled() ) 733 log.trace("acquired("+loadLock.holds()+") for :"+this); 734 } 735 738 protected void release() 739 { 740 if( log.isTraceEnabled() ) 741 log.trace("release("+loadLock.holds()+") for :"+this); 742 loadLock.release(); 743 if( log.isTraceEnabled() ) 744 log.trace("released, holds: "+loadLock.holds()); 745 } 746 747 755 protected byte[] loadByteCode(String classname) 756 throws ClassNotFoundException , IOException 757 { 758 byte[] bytecode = null; 759 URL classURL = getClassURL(classname); 760 761 InputStream is = null; 763 try 764 { 765 is = classURL.openStream(); 766 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 767 byte[] tmp = new byte[1024]; 768 int read = 0; 769 while( (read = is.read(tmp)) > 0 ) 770 { 771 baos.write(tmp, 0, read); 772 } 773 bytecode = baos.toByteArray(); 774 } 775 finally 776 { 777 if( is != null ) 778 is.close(); 779 } 780 781 return bytecode; 782 } 783 784 792 protected byte[] loadByteCode(URL classURL) 793 throws ClassNotFoundException , IOException 794 { 795 byte[] bytecode = null; 796 InputStream is = null; 798 try 799 { 800 is = classURL.openStream(); 801 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 802 byte[] tmp = new byte[1024]; 803 int read = 0; 804 while( (read = is.read(tmp)) > 0 ) 805 { 806 baos.write(tmp, 0, read); 807 } 808 bytecode = baos.toByteArray(); 809 } 810 finally 811 { 812 if( is != null ) 813 is.close(); 814 } 815 816 return bytecode; 817 } 818 819 825 protected ProtectionDomain getProtectionDomain(URL codesourceUrl) 826 { 827 Certificate certs[] = null; 828 CodeSource cs = new CodeSource (codesourceUrl, certs); 829 PermissionCollection permissions = Policy.getPolicy().getPermissions(cs); 830 if (log.isTraceEnabled()) 831 log.trace("getProtectionDomain, url=" + codesourceUrl + 832 " codeSource=" + cs + " permissions=" + permissions); 833 return new ProtectionDomain (cs, permissions); 834 } 835 836 838 840 private URL getCodeSourceURL(String classname, URL classURL) throws java.net.MalformedURLException 841 { 842 String classRsrcName = classname.replace('.', '/') + ".class"; 843 String urlAsString = classURL.toString(); 844 int idx = urlAsString.indexOf(classRsrcName); 845 if (idx == -1) return classURL; 846 urlAsString = urlAsString.substring(0, idx); 847 return new URL (urlAsString); 848 } 849 850 private URL getClassURL(String classname) throws ClassNotFoundException 851 { 852 String classRsrcName = classname.replace('.', '/') + ".class"; 853 URL classURL = this.getResourceLocally(classRsrcName); 854 if( classURL == null ) 855 { 856 String msg = "Failed to find: "+classname+" as resource: "+classRsrcName; 857 throw new ClassNotFoundException (msg); 858 } 859 return classURL; 860 } 861 862 } 864 | Popular Tags |