| 1 17 18 19 package org.apache.catalina.loader; 20 21 import java.io.ByteArrayInputStream ; 22 import java.io.File ; 23 import java.io.FileOutputStream ; 24 import java.io.FilePermission ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.lang.reflect.Field ; 28 import java.lang.reflect.Modifier ; 29 import java.net.MalformedURLException ; 30 import java.net.URL ; 31 import java.net.URLClassLoader ; 32 import java.security.AccessControlException ; 33 import java.security.AccessController ; 34 import java.security.CodeSource ; 35 import java.security.Permission ; 36 import java.security.PermissionCollection ; 37 import java.security.Policy ; 38 import java.security.PrivilegedAction ; 39 import java.sql.Driver ; 40 import java.sql.DriverManager ; 41 import java.sql.SQLException ; 42 import java.util.ArrayList ; 43 import java.util.Enumeration ; 44 import java.util.HashMap ; 45 import java.util.Iterator ; 46 import java.util.Vector ; 47 import java.util.jar.Attributes ; 48 import java.util.jar.JarEntry ; 49 import java.util.jar.JarFile ; 50 import java.util.jar.Manifest ; 51 import java.util.jar.Attributes.Name; 52 53 import javax.naming.NameClassPair ; 54 import javax.naming.NamingEnumeration ; 55 import javax.naming.NamingException ; 56 import javax.naming.directory.DirContext ; 57 58 import org.apache.catalina.Lifecycle; 59 import org.apache.catalina.LifecycleException; 60 import org.apache.catalina.LifecycleListener; 61 import org.apache.catalina.util.StringManager; 62 import org.apache.naming.JndiPermission; 63 import org.apache.naming.resources.Resource; 64 import org.apache.naming.resources.ResourceAttributes; 65 import org.apache.tomcat.util.IntrospectionUtils; 66 67 104 public class WebappClassLoader 105 extends URLClassLoader  106 implements Reloader, Lifecycle 107 { 108 109 protected static org.apache.commons.logging.Log log= 110 org.apache.commons.logging.LogFactory.getLog( WebappClassLoader.class ); 111 112 protected class PrivilegedFindResource 113 implements PrivilegedAction { 114 115 protected File file; 116 protected String path; 117 118 PrivilegedFindResource(File file, String path) { 119 this.file = file; 120 this.path = path; 121 } 122 123 public Object run() { 124 return findResourceInternal(file, path); 125 } 126 127 } 128 129 130 132 133 141 protected static final String [] triggers = { 142 "javax.servlet.Servlet" }; 144 145 146 150 protected static final String [] packageTriggers = { 151 }; 152 153 154 157 protected static final StringManager sm = 158 StringManager.getManager(Constants.Package); 159 160 161 165 boolean antiJARLocking = false; 166 167 168 170 171 175 public WebappClassLoader() { 176 177 super(new URL [0]); 178 this.parent = getParent(); 179 system = getSystemClassLoader(); 180 securityManager = System.getSecurityManager(); 181 182 if (securityManager != null) { 183 refreshPolicy(); 184 } 185 186 } 187 188 189 193 public WebappClassLoader(ClassLoader parent) { 194 195 super(new URL [0], parent); 196 197 this.parent = getParent(); 198 199 system = getSystemClassLoader(); 200 securityManager = System.getSecurityManager(); 201 202 if (securityManager != null) { 203 refreshPolicy(); 204 } 205 } 206 207 208 210 211 215 protected DirContext resources = null; 216 217 218 222 protected HashMap resourceEntries = new HashMap (); 223 224 225 228 protected HashMap notFoundResources = new HashMap (); 229 230 231 239 protected boolean delegate = false; 240 241 242 245 protected long lastJarAccessed = 0L; 246 247 248 252 protected String [] repositories = new String [0]; 253 254 255 258 protected URL [] repositoryURLs = null; 259 260 261 266 protected File [] files = new File [0]; 267 268 269 273 protected JarFile [] jarFiles = new JarFile [0]; 274 275 276 280 protected File [] jarRealFiles = new File [0]; 281 282 283 286 protected String jarPath = null; 287 288 289 293 protected String [] jarNames = new String [0]; 294 295 296 300 protected long[] lastModifiedDates = new long[0]; 301 302 303 307 protected String [] paths = new String [0]; 308 309 310 314 protected ArrayList permissionList = new ArrayList (); 315 316 317 320 protected File loaderDir = null; 321 322 323 327 protected HashMap loaderPC = new HashMap (); 328 329 330 333 protected SecurityManager securityManager = null; 334 335 336 339 protected ClassLoader parent = null; 340 341 342 345 protected ClassLoader system = null; 346 347 348 351 protected boolean started = false; 352 353 354 357 protected boolean hasExternalRepositories = false; 358 359 362 protected boolean needConvert = false; 363 364 365 368 protected Permission allPermission = new java.security.AllPermission (); 369 370 371 373 374 377 public DirContext getResources() { 378 379 return this.resources; 380 381 } 382 383 384 387 public void setResources(DirContext resources) { 388 389 this.resources = resources; 390 391 } 392 393 394 397 public boolean getDelegate() { 398 399 return (this.delegate); 400 401 } 402 403 404 409 public void setDelegate(boolean delegate) { 410 411 this.delegate = delegate; 412 413 } 414 415 416 419 public boolean getAntiJARLocking() { 420 return antiJARLocking; 421 } 422 423 424 427 public void setAntiJARLocking(boolean antiJARLocking) { 428 this.antiJARLocking = antiJARLocking; 429 } 430 431 432 438 public void addPermission(String path) { 439 if (path == null) { 440 return; 441 } 442 443 if (securityManager != null) { 444 Permission permission = null; 445 if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) { 446 if (!path.endsWith("/")) { 447 path = path + "/"; 448 } 449 permission = new JndiPermission(path + "*"); 450 addPermission(permission); 451 } else { 452 if (!path.endsWith(File.separator)) { 453 permission = new FilePermission (path, "read"); 454 addPermission(permission); 455 path = path + File.separator; 456 } 457 permission = new FilePermission (path + "-", "read"); 458 addPermission(permission); 459 } 460 } 461 } 462 463 464 470 public void addPermission(URL url) { 471 if (url != null) { 472 addPermission(url.toString()); 473 } 474 } 475 476 477 482 public void addPermission(Permission permission) { 483 if ((securityManager != null) && (permission != null)) { 484 permissionList.add(permission); 485 } 486 } 487 488 489 492 public String getJarPath() { 493 494 return this.jarPath; 495 496 } 497 498 499 502 public void setJarPath(String jarPath) { 503 504 this.jarPath = jarPath; 505 506 } 507 508 509 512 public void setWorkDir(File workDir) { 513 this.loaderDir = new File (workDir, "loader"); 514 } 515 516 520 protected void setParentClassLoader(ClassLoader pcl) { 521 parent = pcl; 522 } 523 524 526 527 537 public void addRepository(String repository) { 538 539 if (repository.startsWith("/WEB-INF/lib") 542 || repository.startsWith("/WEB-INF/classes")) 543 return; 544 545 try { 547 URL url = new URL (repository); 548 super.addURL(url); 549 hasExternalRepositories = true; 550 repositoryURLs = null; 551 } catch (MalformedURLException e) { 552 IllegalArgumentException iae = new IllegalArgumentException  553 ("Invalid repository: " + repository); 554 iae.initCause(e); 555 throw iae; 556 } 557 558 } 559 560 561 571 synchronized void addRepository(String repository, File file) { 572 573 576 if (repository == null) 577 return; 578 579 if (log.isDebugEnabled()) 580 log.debug("addRepository(" + repository + ")"); 581 582 int i; 583 584 String [] result = new String [repositories.length + 1]; 586 for (i = 0; i < repositories.length; i++) { 587 result[i] = repositories[i]; 588 } 589 result[repositories.length] = repository; 590 repositories = result; 591 592 File [] result2 = new File [files.length + 1]; 594 for (i = 0; i < files.length; i++) { 595 result2[i] = files[i]; 596 } 597 result2[files.length] = file; 598 files = result2; 599 600 } 601 602 603 synchronized void addJar(String jar, JarFile jarFile, File file) 604 throws IOException { 605 606 if (jar == null) 607 return; 608 if (jarFile == null) 609 return; 610 if (file == null) 611 return; 612 613 if (log.isDebugEnabled()) 614 log.debug("addJar(" + jar + ")"); 615 616 int i; 617 618 if ((jarPath != null) && (jar.startsWith(jarPath))) { 619 620 String jarName = jar.substring(jarPath.length()); 621 while (jarName.startsWith("/")) 622 jarName = jarName.substring(1); 623 624 String [] result = new String [jarNames.length + 1]; 625 for (i = 0; i < jarNames.length; i++) { 626 result[i] = jarNames[i]; 627 } 628 result[jarNames.length] = jarName; 629 jarNames = result; 630 631 } 632 633 try { 634 635 637 long lastModified = 638 ((ResourceAttributes) resources.getAttributes(jar)) 639 .getLastModified(); 640 641 String [] result = new String [paths.length + 1]; 642 for (i = 0; i < paths.length; i++) { 643 result[i] = paths[i]; 644 } 645 result[paths.length] = jar; 646 paths = result; 647 648 long[] result3 = new long[lastModifiedDates.length + 1]; 649 for (i = 0; i < lastModifiedDates.length; i++) { 650 result3[i] = lastModifiedDates[i]; 651 } 652 result3[lastModifiedDates.length] = lastModified; 653 lastModifiedDates = result3; 654 655 } catch (NamingException e) { 656 } 658 659 if (!validateJarFile(file)) 662 return; 663 664 JarFile [] result2 = new JarFile [jarFiles.length + 1]; 665 for (i = 0; i < jarFiles.length; i++) { 666 result2[i] = jarFiles[i]; 667 } 668 result2[jarFiles.length] = jarFile; 669 jarFiles = result2; 670 671 File [] result4 = new File [jarRealFiles.length + 1]; 673 for (i = 0; i < jarRealFiles.length; i++) { 674 result4[i] = jarRealFiles[i]; 675 } 676 result4[jarRealFiles.length] = file; 677 jarRealFiles = result4; 678 } 679 680 681 687 public String [] findRepositories() { 688 689 return ((String [])repositories.clone()); 690 691 } 692 693 694 698 public boolean modified() { 699 700 if (log.isDebugEnabled()) 701 log.debug("modified()"); 702 703 int length = paths.length; 705 706 int length2 = lastModifiedDates.length; 710 if (length > length2) 711 length = length2; 712 713 for (int i = 0; i < length; i++) { 714 try { 715 long lastModified = 716 ((ResourceAttributes) resources.getAttributes(paths[i])) 717 .getLastModified(); 718 if (lastModified != lastModifiedDates[i]) { 719 if( log.isDebugEnabled() ) 720 log.debug(" Resource '" + paths[i] 721 + "' was modified; Date is now: " 722 + new java.util.Date (lastModified) + " Was: " 723 + new java.util.Date (lastModifiedDates[i])); 724 return (true); 725 } 726 } catch (NamingException e) { 727 log.error(" Resource '" + paths[i] + "' is missing"); 728 return (true); 729 } 730 } 731 732 length = jarNames.length; 733 734 if (getJarPath() != null) { 736 737 try { 738 NamingEnumeration enumeration = resources.listBindings(getJarPath()); 739 int i = 0; 740 while (enumeration.hasMoreElements() && (i < length)) { 741 NameClassPair ncPair = (NameClassPair ) enumeration.nextElement(); 742 String name = ncPair.getName(); 743 if (!name.endsWith(".jar")) 745 continue; 746 if (!name.equals(jarNames[i])) { 747 log.info(" Additional JARs have been added : '" 749 + name + "'"); 750 return (true); 751 } 752 i++; 753 } 754 if (enumeration.hasMoreElements()) { 755 while (enumeration.hasMoreElements()) { 756 NameClassPair ncPair = 757 (NameClassPair ) enumeration.nextElement(); 758 String name = ncPair.getName(); 759 if (name.endsWith(".jar")) { 761 log.info(" Additional JARs have been added"); 763 return (true); 764 } 765 } 766 } else if (i < jarNames.length) { 767 log.info(" Additional JARs have been added"); 769 return (true); 770 } 771 } catch (NamingException e) { 772 if (log.isDebugEnabled()) 773 log.debug(" Failed tracking modifications of '" 774 + getJarPath() + "'"); 775 } catch (ClassCastException e) { 776 log.error(" Failed tracking modifications of '" 777 + getJarPath() + "' : " + e.getMessage()); 778 } 779 780 } 781 782 return (false); 784 785 } 786 787 788 791 public String toString() { 792 793 StringBuffer sb = new StringBuffer ("WebappClassLoader\r\n"); 794 sb.append(" delegate: "); 795 sb.append(delegate); 796 sb.append("\r\n"); 797 sb.append(" repositories:\r\n"); 798 if (repositories != null) { 799 for (int i = 0; i < repositories.length; i++) { 800 sb.append(" "); 801 sb.append(repositories[i]); 802 sb.append("\r\n"); 803 } 804 } 805 if (this.parent != null) { 806 sb.append("----------> Parent Classloader:\r\n"); 807 sb.append(this.parent.toString()); 808 sb.append("\r\n"); 809 } 810 return (sb.toString()); 811 812 } 813 814 815 817 818 821 protected void addURL(URL url) { 822 super.addURL(url); 823 hasExternalRepositories = true; 824 repositoryURLs = null; 825 } 826 827 828 836 public Class findClass(String name) throws ClassNotFoundException { 837 838 if (log.isDebugEnabled()) 839 log.debug(" findClass(" + name + ")"); 840 841 if (!started) { 843 throw new ClassNotFoundException (name); 844 } 845 846 if (securityManager != null) { 848 int i = name.lastIndexOf('.'); 849 if (i >= 0) { 850 try { 851 if (log.isTraceEnabled()) 852 log.trace(" securityManager.checkPackageDefinition"); 853 securityManager.checkPackageDefinition(name.substring(0,i)); 854 } catch (Exception se) { 855 if (log.isTraceEnabled()) 856 log.trace(" -->Exception-->ClassNotFoundException", se); 857 throw new ClassNotFoundException (name, se); 858 } 859 } 860 } 861 862 Class clazz = null; 865 try { 866 if (log.isTraceEnabled()) 867 log.trace(" findClassInternal(" + name + ")"); 868 try { 869 clazz = findClassInternal(name); 870 } catch(ClassNotFoundException cnfe) { 871 if (!hasExternalRepositories) { 872 throw cnfe; 873 } 874 } catch(AccessControlException ace) { 875
|