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 throw new ClassNotFoundException (name, ace); 876 } catch (RuntimeException e) { 877 if (log.isTraceEnabled()) 878 log.trace(" -->RuntimeException Rethrown", e); 879 throw e; 880 } 881 if ((clazz == null) && hasExternalRepositories) { 882 try { 883 clazz = super.findClass(name); 884 } catch(AccessControlException ace) { 885 throw new ClassNotFoundException (name, ace); 886 } catch (RuntimeException e) { 887 if (log.isTraceEnabled()) 888 log.trace(" -->RuntimeException Rethrown", e); 889 throw e; 890 } 891 } 892 if (clazz == null) { 893 if (log.isDebugEnabled()) 894 log.debug(" --> Returning ClassNotFoundException"); 895 throw new ClassNotFoundException (name); 896 } 897 } catch (ClassNotFoundException e) { 898 if (log.isTraceEnabled()) 899 log.trace(" --> Passing on ClassNotFoundException"); 900 throw e; 901 } 902 903 if (log.isTraceEnabled()) 905 log.debug(" Returning class " + clazz); 906 if ((log.isTraceEnabled()) && (clazz != null)) 907 log.debug(" Loaded by " + clazz.getClassLoader()); 908 return (clazz); 909 910 } 911 912 913 920 public URL findResource(final String name) { 921 922 if (log.isDebugEnabled()) 923 log.debug(" findResource(" + name + ")"); 924 925 URL url = null; 926 927 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); 928 if (entry == null) { 929 entry = findResourceInternal(name, name); 930 } 931 if (entry != null) { 932 url = entry.source; 933 } 934 935 if ((url == null) && hasExternalRepositories) 936 url = super.findResource(name); 937 938 if (log.isDebugEnabled()) { 939 if (url != null) 940 log.debug(" --> Returning '" + url.toString() + "'"); 941 else 942 log.debug(" --> Resource not found, returning null"); 943 } 944 return (url); 945 946 } 947 948 949 958 public Enumeration findResources(String name) throws IOException { 959 960 if (log.isDebugEnabled()) 961 log.debug(" findResources(" + name + ")"); 962 963 Vector result = new Vector (); 964 965 int jarFilesLength = jarFiles.length; 966 int repositoriesLength = repositories.length; 967 968 int i; 969 970 for (i = 0; i < repositoriesLength; i++) { 972 try { 973 String fullPath = repositories[i] + name; 974 resources.lookup(fullPath); 975 try { 978 result.addElement(getURI(new File (files[i], name))); 979 } catch (MalformedURLException e) { 980 } 982 } catch (NamingException e) { 983 } 984 } 985 986 synchronized (jarFiles) { 988 if (openJARs()) { 989 for (i = 0; i < jarFilesLength; i++) { 990 JarEntry jarEntry = jarFiles[i].getJarEntry(name); 991 if (jarEntry != null) { 992 try { 993 String jarFakeUrl = getURI(jarRealFiles[i]).toString(); 994 jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name; 995 result.addElement(new URL (jarFakeUrl)); 996 } catch (MalformedURLException e) { 997 } 999 } 1000 } 1001 } 1002 } 1003 1004 if (hasExternalRepositories) { 1006 1007 Enumeration otherResourcePaths = super.findResources(name); 1008 1009 while (otherResourcePaths.hasMoreElements()) { 1010 result.addElement(otherResourcePaths.nextElement()); 1011 } 1012 1013 } 1014 1015 return result.elements(); 1016 1017 } 1018 1019 1020 1042 public URL getResource(String name) { 1043 1044 if (log.isDebugEnabled()) 1045 log.debug("getResource(" + name + ")"); 1046 URL url = null; 1047 1048 if (delegate) { 1050 if (log.isDebugEnabled()) 1051 log.debug(" Delegating to parent classloader " + parent); 1052 ClassLoader loader = parent; 1053 if (loader == null) 1054 loader = system; 1055 url = loader.getResource(name); 1056 if (url != null) { 1057 if (log.isDebugEnabled()) 1058 log.debug(" --> Returning '" + url.toString() + "'"); 1059 return (url); 1060 } 1061 } 1062 1063 url = findResource(name); 1065 if (url != null) { 1066 if (antiJARLocking) { 1069 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); 1070 try { 1071 String repository = entry.codeBase.toString(); 1072 if ((repository.endsWith(".jar")) 1073 && (!(name.endsWith(".class")))) { 1074 File resourceFile = new File (loaderDir, name); 1076 url = getURI(resourceFile); 1077 } 1078 } catch (Exception e) { 1079 } 1081 } 1082 if (log.isDebugEnabled()) 1083 log.debug(" --> Returning '" + url.toString() + "'"); 1084 return (url); 1085 } 1086 1087 if( !delegate ) { 1089 ClassLoader loader = parent; 1090 if (loader == null) 1091 loader = system; 1092 url = loader.getResource(name); 1093 if (url != null) { 1094 if (log.isDebugEnabled()) 1095 log.debug(" --> Returning '" + url.toString() + "'"); 1096 return (url); 1097 } 1098 } 1099 1100 if (log.isDebugEnabled()) 1102 log.debug(" --> Resource not found, returning null"); 1103 return (null); 1104 1105 } 1106 1107 1108 1117 public InputStream getResourceAsStream(String name) { 1118 1119 if (log.isDebugEnabled()) 1120 log.debug("getResourceAsStream(" + name + ")"); 1121 InputStream stream = null; 1122 1123 stream = findLoadedResource(name); 1125 if (stream != null) { 1126 if (log.isDebugEnabled()) 1127 log.debug(" --> Returning stream from cache"); 1128 return (stream); 1129 } 1130 1131 if (delegate) { 1133 if (log.isDebugEnabled()) 1134 log.debug(" Delegating to parent classloader " + parent); 1135 ClassLoader loader = parent; 1136 if (loader == null) 1137 loader = system; 1138 stream = loader.getResourceAsStream(name); 1139 if (stream != null) { 1140 if (log.isDebugEnabled()) 1142 log.debug(" --> Returning stream from parent"); 1143 return (stream); 1144 } 1145 } 1146 1147 if (log.isDebugEnabled()) 1149 log.debug(" Searching local repositories"); 1150 URL url = findResource(name); 1151 if (url != null) { 1152 if (log.isDebugEnabled()) 1154 log.debug(" --> Returning stream from local"); 1155 stream = findLoadedResource(name); 1156 try { 1157 if (hasExternalRepositories && (stream == null)) 1158 stream = url.openStream(); 1159 } catch (IOException e) { 1160 ; } 1162 if (stream != null) 1163 return (stream); 1164 } 1165 1166 if (!delegate) { 1168 if (log.isDebugEnabled()) 1169 log.debug(" Delegating to parent classloader unconditionally " + parent); 1170 ClassLoader loader = parent; 1171 if (loader == null) 1172 loader = system; 1173 stream = loader.getResourceAsStream(name); 1174 if (stream != null) { 1175 if (log.isDebugEnabled()) 1177 log.debug(" --> Returning stream from parent"); 1178 return (stream); 1179 } 1180 } 1181 1182 if (log.isDebugEnabled()) 1184 log.debug(" --> Resource not found, returning null"); 1185 return (null); 1186 1187 } 1188 1189 1190 1199 public Class loadClass(String name) throws ClassNotFoundException { 1200 1201 return (loadClass(name, false)); 1202 1203 } 1204 1205 1206 1231 public Class loadClass(String name, boolean resolve) 1232 throws ClassNotFoundException { 1233 1234 if (log.isDebugEnabled()) 1235 log.debug("loadClass(" + name + ", " + resolve + ")"); 1236 Class clazz = null; 1237 1238 if (!started) { 1240 try { 1241 throw new IllegalStateException (); 1242 } catch (IllegalStateException e) { 1243 log.info(sm.getString("webappClassLoader.stopped", name), e); 1244 } 1245 } 1246 1247 clazz = findLoadedClass0(name); 1249 if (clazz != null) { 1250 if (log.isDebugEnabled()) 1251 log.debug(" Returning class from cache"); 1252 if (resolve) 1253 resolveClass(clazz); 1254 return (clazz); 1255 } 1256 1257 clazz = findLoadedClass(name); 1259 if (clazz != null) { 1260 if (log.isDebugEnabled()) 1261 log.debug(" Returning class from cache"); 1262 if (resolve) 1263 resolveClass(clazz); 1264 return (clazz); 1265 } 1266 1267 try { 1270 clazz = system.loadClass(name); 1271 if (clazz != null) { 1272 if (resolve) 1273 resolveClass(clazz); 1274 return (clazz); 1275 } 1276 } catch (ClassNotFoundException e) { 1277 } 1279 1280 if (securityManager != null) { 1282 int i = name.lastIndexOf('.'); 1283 if (i >= 0) { 1284 try { 1285 securityManager.checkPackageAccess(name.substring(0,i)); 1286 } catch (SecurityException se) { 1287 String error = "Security Violation, attempt to use " + 1288 "Restricted Class: " + name; 1289 log.info(error, se); 1290 throw new ClassNotFoundException (error, se); 1291 } 1292 } 1293 } 1294 1295 boolean delegateLoad = delegate || filter(name); 1296 1297 if (delegateLoad) { 1299 if (log.isDebugEnabled()) 1300 log.debug(" Delegating to parent classloader1 " + parent); 1301 ClassLoader loader = parent; 1302 if (loader == null) 1303 loader = system; 1304 try { 1305 clazz = loader.loadClass(name); 1306 if (clazz != null) { 1307 if (log.isDebugEnabled()) 1308 log.debug(" Loading class from parent"); 1309 if (resolve) 1310 resolveClass(clazz); 1311 return (clazz); 1312 } 1313 } catch (ClassNotFoundException e) { 1314 ; 1315 } 1316 } 1317 1318 if (log.isDebugEnabled()) 1320 log.debug(" Searching local repositories"); 1321 try { 1322 clazz = findClass(name); 1323 if (clazz != null) { 1324 if (log.isDebugEnabled()) 1325 log.debug(" Loading class from local repository"); 1326 if (resolve) 1327 resolveClass(clazz); 1328 return (clazz); 1329 } 1330 } catch (ClassNotFoundException e) { 1331 ; 1332 } 1333 1334 if (!delegateLoad) { 1336 if (log.isDebugEnabled()) 1337 log.debug(" Delegating to parent classloader at end: " + parent); 1338 ClassLoader loader = parent; 1339 if (loader == null) 1340 loader = system; 1341 try { 1342 clazz = loader.loadClass(name); 1343 if (clazz != null) { 1344 if (log.isDebugEnabled()) 1345 log.debug(" Loading class from parent"); 1346 if (resolve) 1347 resolveClass(clazz); 1348 return (clazz); 1349 } 1350 } catch (ClassNotFoundException e) { 1351 ; 1352 } 1353 } 1354 1355 throw new ClassNotFoundException (name); 1356 } 1357 1358 1359 1369 protected PermissionCollection getPermissions(CodeSource codeSource) { 1370 1371 String codeUrl = codeSource.getLocation().toString(); 1372 PermissionCollection pc; 1373 if ((pc = (PermissionCollection )loaderPC.get(codeUrl)) == null) { 1374 pc = super.getPermissions(codeSource); 1375 if (pc != null) { 1376 Iterator perms = permissionList.iterator(); 1377 while (perms.hasNext()) { 1378 Permission p = (Permission )perms.next(); 1379 pc.add(p); 1380 } 1381 loaderPC.put(codeUrl,pc); 1382 } 1383 } 1384 return (pc); 1385 1386 } 1387 1388 1389 1395 public URL [] getURLs() { 1396 1397 if (repositoryURLs != null) { 1398 return repositoryURLs; 1399 } 1400 1401 URL [] external = super.getURLs(); 1402 1403 int filesLength = files.length; 1404 int jarFilesLength = jarRealFiles.length; 1405 int length = filesLength + jarFilesLength + external.length; 1406 int i; 1407 1408 try { 1409 1410 URL [] urls = new URL [length]; 1411 for (i = 0; i < length; i++) { 1412 if (i < filesLength) { 1413 urls[i] = getURL(files[i], true); 1414 } else if (i < filesLength + jarFilesLength) { 1415 urls[i] = getURL(jarRealFiles[i - filesLength], true); 1416 } else { 1417 urls[i] = external[i - filesLength - jarFilesLength]; 1418 } 1419 } 1420 1421 repositoryURLs = urls; 1422 1423 } catch (MalformedURLException e) { 1424 repositoryURLs = new URL [0]; 1425 } 1426 1427 return repositoryURLs; 1428 1429 } 1430 1431 1432 1434 1435 1440 public void addLifecycleListener(LifecycleListener listener) { 1441 } 1442 1443 1444 1448 public LifecycleListener[] findLifecycleListeners() { 1449 return new LifecycleListener[0]; 1450 } 1451 1452 1453 1458 public void removeLifecycleListener(LifecycleListener listener) { 1459 } 1460 1461 1462 1467 public void start() throws LifecycleException { 1468 1469 started = true; 1470 String encoding = null; 1471 try { 1472 encoding = System.getProperty("file.encoding"); 1473 } catch (Exception e) { 1474 return; 1475 } 1476 if (encoding.indexOf("EBCDIC")!=-1) { 1477 needConvert = true; 1478 } 1479 1480 } 1481 1482 1483 1488 public void stop() throws LifecycleException { 1489 1490 clearReferences(); 1493 1494 started = false; 1495 1496 int length = files.length; 1497 for (int i = 0; i < length; i++) { 1498 files[i] = null; 1499 } 1500 1501 length = jarFiles.length; 1502 for (int i = 0; i < length; i++) { 1503 try { 1504 if (jarFiles[i] != null) { 1505 jarFiles[i].close(); 1506 } 1507 } catch (IOException e) { 1508 } 1510 jarFiles[i] = null; 1511 } 1512 1513 notFoundResources.clear(); 1514 resourceEntries.clear(); 1515 resources = null; 1516 repositories = null; 1517 repositoryURLs = null; 1518 files = null; 1519 jarFiles = null; 1520 jarRealFiles = null; 1521 jarPath = null; 1522 jarNames = null; 1523 lastModifiedDates = null; 1524 paths = null; 1525 hasExternalRepositories = false; 1526 parent = null; 1527 1528 permissionList.clear(); 1529 loaderPC.clear(); 1530 1531 if (loaderDir != null) { 1532 deleteDir(loaderDir); 1533 } 1534 1535 } 1536 1537 1538 1542 public void closeJARs(boolean force) { 1543 if (jarFiles.length > 0) { 1544 synchronized (jarFiles) { 1545 if (force || (System.currentTimeMillis() 1546 > (lastJarAccessed + 90000))) { 1547 for (int i = 0; i < jarFiles.length; i++) { 1548 try { 1549 if (jarFiles[i] != null) { 1550 jarFiles[i].close(); 1551 jarFiles[i] = null; 1552 } 1553 } catch (IOException e) { 1554 if (log.isDebugEnabled()) { 1555 log.debug("Failed to close JAR", e); 1556 } 1557 } 1558 } 1559 } 1560 } 1561 } 1562 } 1563 1564 1565 1567 1568 1571 protected void clearReferences() { 1572 1573 Enumeration drivers = DriverManager.getDrivers(); 1575 while (drivers.hasMoreElements()) { 1576 Driver driver = (Driver ) drivers.nextElement(); 1577 if (driver.getClass().getClassLoader() == this) { 1578 try { 1579 DriverManager.deregisterDriver(driver); 1580 } catch (SQLException e) { 1581 log.warn("SQL driver deregistration failed", e); 1582 } 1583 } 1584 } 1585 1586 Iterator loadedClasses = ((HashMap ) resourceEntries.clone()).values().iterator(); 1589 while (loadedClasses.hasNext()) { 1590 ResourceEntry entry = (ResourceEntry) loadedClasses.next(); 1591 if (entry.loadedClass != null) { 1592 Class clazz = entry.loadedClass; 1593 try { 1594 Field [] fields = clazz.getDeclaredFields(); 1595 for (int i = 0; i < fields.length; i++) { 1596 Field field = fields[i]; 1597 int mods = field.getModifiers(); 1598 if (field.getType().isPrimitive() 1599 || (field.getName().indexOf("$") != -1)) { 1600 continue; 1601 } 1602 if (Modifier.isStatic(mods)) { 1603 try { 1604 field.setAccessible(true); 1605 if (Modifier.isFinal(mods)) { 1606 if (!((field.getType().getName().startsWith("java.")) 1607 || (field.getType().getName().startsWith("javax.")))) { 1608 nullInstance(field.get(null)); 1609 } 1610 } else { 1611 field.set(null, null); 1612 if (log.isDebugEnabled()) { 1613 log.debug("Set field " + field.getName() 1614 + " to null in class " + clazz.getName()); 1615 } 1616 } 1617 } catch (Throwable t) { 1618 if (log.isDebugEnabled()) { 1619 log.debug("Could not set field " + field.getName() 1620 + " to null in class " + clazz.getName(), t); 1621 } 1622 } 1623 } 1624 } 1625 } catch (Throwable t) { 1626 if (log.isDebugEnabled()) { 1627 log.debug("Could not clean fields for class " + clazz.getName(), t); 1628 } 1629 } 1630 } 1631 } 1632 1633 IntrospectionUtils.clear(); 1635 1636 org.apache.commons.logging.LogFactory.release(this); 1638 1639 java.beans.Introspector.flushCaches(); 1641 1642 } 1643 1644 1645 protected void nullInstance(Object instance) { 1646 if (instance == null) { 1647 return; 1648 } 1649 Field [] fields = instance.getClass().getDeclaredFields(); 1650 for (int i = 0; i < fields.length; i++) { 1651 Field field = fields[i]; 1652 int mods = field.getModifiers(); 1653 if (field.getType().isPrimitive() 1654 || (field.getName().indexOf("$") != -1)) { 1655 continue; 1656 } 1657 try { 1658 field.setAccessible(true); 1659 if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) { 1660 continue; 1662 } else { 1663 Object value = field.get(instance); 1664 if (null != value) { 1665 Class valueClass = value.getClass(); 1666 if (!loadedByThisOrChild(valueClass)) { 1667 if (log.isDebugEnabled()) { 1668 log.debug("Not setting field " + field.getName() + 1669 " to null in object of class " + 1670 instance.getClass().getName() + 1671 " because the referenced object was of type " + 1672 valueClass.getName() + 1673 " which was not loaded by this WebappClassLoader."); 1674 } 1675 } else { 1676 field.set(instance, null); 1677 if (log.isDebugEnabled()) { 1678 log.debug("Set field " + field.getName() 1679 + " to null in class " + instance.getClass().getName()); 1680 } 1681 } 1682 } 1683 } 1684 } catch (Throwable t) { 1685 if (log.isDebugEnabled()) { 1686 log.debug("Could not set field " + field.getName() 1687 + " to null in object instance of class " 1688 + instance.getClass().getName(), t); 1689 } 1690 } 1691 } 1692 } 1693 1694 1695 1699 protected boolean loadedByThisOrChild(Class clazz) 1700 { 1701 boolean result = false; 1702 for (ClassLoader classLoader = clazz.getClassLoader(); 1703 null != classLoader; classLoader = classLoader.getParent()) { 1704 if (classLoader.equals(this)) { 1705 result = true; 1706 break; 1707 } 1708 } 1709 return result; 1710 } 1711 1712 1713 1716 protected boolean openJARs() { 1717 if (started && (jarFiles.length > 0)) { 1718 lastJarAccessed = System.currentTimeMillis(); 1719 if (jarFiles[0] == null) { 1720 for (int i = 0; i < jarFiles.length; i++) { 1721 try { 1722 jarFiles[i] = new JarFile (jarRealFiles[i]); 1723 } catch (IOException e) { 1724 if (log.isDebugEnabled()) { 1725 log.debug("Failed to open JAR", e); 1726 } 1727 return false; 1728 } 1729 } 1730 } 1731 } 1732 return true; 1733 } 1734 1735 1736 1741 protected Class findClassInternal(String name) 1742 throws ClassNotFoundException { 1743 1744 if (!validate(name)) 1745 throw new ClassNotFoundException (name); 1746 1747 String tempPath = name.replace('.', '/'); 1748 String classPath = tempPath + ".class"; 1749 1750 ResourceEntry entry = null; 1751 1752 entry = findResourceInternal(name, classPath); 1753 1754 if (entry == null) 1755 throw new ClassNotFoundException (name); 1756 1757 Class clazz = entry.loadedClass; 1758 if (clazz != null) 1759 return clazz; 1760 1761 synchronized (entry) { 1762 if (entry.binaryContent == null && entry.loadedClass == null) 1763 throw new ClassNotFoundException (name); 1764 1765 String packageName = null; 1767 int pos = name.lastIndexOf('.'); 1768 if (pos != -1) 1769 packageName = name.substring(0, pos); 1770 1771 Package pkg = null; 1772 1773 if (packageName != null) { 1774 synchronized (this) { 1775 pkg = getPackage(packageName); 1776 1777 if (pkg == null) { 1779 if (entry.manifest == null) { 1780 definePackage(packageName, null, null, null, null, 1781 null, null, null); 1782 } else { 1783 definePackage(packageName, entry.manifest, 1784 entry.codeBase); 1785 } 1786 } 1787 } 1788 } 1789 1790 if (securityManager != null) { 1791 1792 if (pkg != null) { 1794 boolean sealCheck = true; 1795 if (pkg.isSealed()) { 1796 sealCheck = pkg.isSealed(entry.codeBase); 1797 } else { 1798 sealCheck = (entry.manifest == null) 1799 || !isPackageSealed(packageName, entry.manifest); 1800 } 1801 if (!sealCheck) 1802 throw new SecurityException 1803 ("Sealing violation loading " + name + " : Package " 1804 + packageName + " is sealed."); 1805 } 1806 1807 } 1808 1809 if (entry.loadedClass == null) { 1810 clazz = defineClass(name, entry.binaryContent, 0, 1811 entry.binaryContent.length, 1812 new CodeSource (entry.codeBase, entry.certificates)); 1813 entry.loadedClass = clazz; 1814 entry.binaryContent = null; 1815 entry.source = null; 1816 entry.codeBase = null; 1817 entry.manifest = null; 1818 entry.certificates = null; 1819 } else { 1820 clazz = entry.loadedClass; 1821 } 1822 } 1823 1824 return clazz; 1825 1826 } 1827 1828 1834 protected ResourceEntry findResourceInternal(File file, String path){ 1835 ResourceEntry entry = new ResourceEntry(); 1836 try { 1837 entry.source = getURI(new File (file, path)); 1838 entry.codeBase = getURL(new File (file, path), false); 1839 } catch (MalformedURLException e) { 1840 return null; 1841 } 1842 return entry; 1843 } 1844 1845 1846 1851 protected ResourceEntry findResourceInternal(String name, String path) { 1852 1853 if (!started) { 1854 log.info(sm.getString("webappClassLoader.stopped", name)); 1855 return null; 1856 } 1857 1858 if ((name == null) || (path == null)) 1859 return null; 1860 1861 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); 1862 if (entry != null) 1863 return entry; 1864 1865 int contentLength = -1; 1866 InputStream binaryStream = null; 1867 1868 int jarFilesLength = jarFiles.length; 1869 int repositoriesLength = repositories.length; 1870 1871 int i; 1872 1873 Resource resource = null; 1874 1875 boolean fileNeedConvert = false; 1876 1877 for (i = 0; (entry == null) && (i < repositoriesLength); i++) { 1878 try { 1879 1880 String fullPath = repositories[i] + path; 1881 1882 Object lookupResult = resources.lookup(fullPath); 1883 if (lookupResult instanceof Resource) { 1884 resource = (Resource) lookupResult; 1885 } 1886 1887 if (securityManager != null) { 1890 PrivilegedAction dp = 1891 new PrivilegedFindResource(files[i], path); 1892 entry = (ResourceEntry)AccessController.doPrivileged(dp); 1893 } else { 1894 entry = findResourceInternal(files[i], path); 1895 } 1896 1897 ResourceAttributes attributes = 1898 (ResourceAttributes) resources.getAttributes(fullPath); 1899 contentLength = (int) attributes.getContentLength(); 1900 entry.lastModified = attributes.getLastModified(); 1901 1902 if (resource != null) { 1903 1904 1905 try { 1906 binaryStream = resource.streamContent(); 1907 } catch (IOException e) { 1908 return null; 1909 } 1910 1911 if (needConvert) { 1912 if (path.endsWith(".properties")) { 1913 fileNeedConvert = true; 1914 } 1915 } 1916 1917 synchronized (allPermission) { 1920 1921 int j; 1922 1923 long[] result2 = 1924 new long[lastModifiedDates.length + 1]; 1925 for (j = 0; j < lastModifiedDates.length; j++) { 1926 result2[j] = lastModifiedDates[j]; 1927 } 1928 result2[lastModifiedDates.length] = entry.lastModified; 1929 lastModifiedDates = result2; 1930 1931 String [] result = new String [paths.length + 1]; 1932 for (j = 0; j < paths.length; j++) { 1933 result[j] = paths[j]; 1934 } 1935 result[paths.length] = fullPath; 1936 paths = result; 1937 1938 } 1939 1940 } 1941 1942 } catch (NamingException e) { 1943 } 1944 } 1945 1946 if ((entry == null) && (notFoundResources.containsKey(name))) 1947 return null; 1948 1949 JarEntry jarEntry = null; 1950 1951 synchronized (jarFiles) { 1952 1953 if (!openJARs()) { 1954 return null; 1955 } 1956 for (i = 0; (entry == null) && (i < jarFilesLength); i++) { 1957 1958 jarEntry = jarFiles[i].getJarEntry(path); 1959 1960 if (jarEntry != null) { 1961 1962 entry = new ResourceEntry(); 1963 try { 1964 entry.codeBase = getURL(jarRealFiles[i], false); 1965 String jarFakeUrl = getURI(jarRealFiles[i]).toString(); 1966 jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path; 1967 entry.source = new URL (jarFakeUrl); 1968 entry.lastModified = jarRealFiles[i].lastModified(); 1969 } catch (MalformedURLException e) { 1970 return null; 1971 } 1972 contentLength = (int) jarEntry.getSize(); 1973 try { 1974 entry.manifest = jarFiles[i].getManifest(); 1975 binaryStream = jarFiles[i].getInputStream(jarEntry); 1976 } catch (IOException e) { 1977 return null; 1978 } 1979 1980 if (antiJARLocking && !(path.endsWith(".class"))) { 1982 byte[] buf = new byte[1024]; 1983 File resourceFile = new File 1984 (loaderDir, jarEntry.getName()); 1985 if (!resourceFile.exists()) { 1986 Enumeration entries = jarFiles[i].entries(); 1987 while (entries.hasMoreElements()) { 1988 JarEntry jarEntry2 = 1989 (JarEntry ) entries.nextElement(); 1990 if (!(jarEntry2.isDirectory()) 1991 && (!jarEntry2.getName().endsWith 1992 (".class"))) { 1993 resourceFile = new File 1994 (loaderDir, jarEntry2.getName()); 1995 resourceFile.getParentFile().mkdirs(); 1996 FileOutputStream os = null; 1997 InputStream is = null; 1998 try { 1999 is = jarFiles[i].getInputStream 2000 (jarEntry2); 2001 os = new FileOutputStream 2002 (resourceFile); 2003 while (true) { 2004 int n = is.read(buf); 2005 if (n <= 0) { 2006 break; 2007 } 2008 os.write(buf, 0, n); 2009 } 2010 } catch (IOException e) { 2011 } finally { 2013 try { 2014 if (is != null) { 2015 is.close(); 2016 } 2017 } catch (IOException e) { 2018 } 2019 try { 2020 if (os != null) { 2021 os.close(); 2022 } 2023 } catch (IOException e) { 2024 } 2025 } 2026 } 2027 } 2028 } 2029 } 2030 2031 } 2032 2033 } 2034 2035 if (entry == null) { 2036 synchronized (notFoundResources) { 2037 notFoundResources.put(name, name); 2038 } 2039 return null; 2040 } 2041 2042 if (binaryStream != null) { 2043 2044 byte[] binaryContent = new byte[contentLength]; 2045 2046 int pos = 0; 2047 try { 2048 2049 while (true) { 2050 int n = binaryStream.read(binaryContent, pos, 2051 binaryContent.length - pos); 2052 if (n <= 0) 2053 break; 2054 pos += n; 2055 } 2056 binaryStream.close(); 2057 } catch (IOException e) { 2058 e.printStackTrace(); 2059 return null; 2060 } catch (Exception e) { 2061 e.printStackTrace(); 2062 return null; 2063 } 2064 2065 if (fileNeedConvert) { 2066 String str = new String (binaryContent,0,pos); 2067 try { 2068 binaryContent = str.getBytes("UTF-8"); 2069 } catch (Exception e) { 2070 return null; 2071 } 2072 } 2073 entry.binaryContent = binaryContent; 2074 2075 if (jarEntry != null) { 2078 entry.certificates = jarEntry.getCertificates(); 2079 } 2080 2081 } 2082 2083 } 2084 2085 synchronized (resourceEntries) { 2087 ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name); 2091 if (entry2 == null) { 2092 resourceEntries.put(name, entry); 2093 } else { 2094 entry = entry2; 2095 } 2096 } 2097 2098 return entry; 2099 2100 } 2101 2102 2103 2107 protected boolean isPackageSealed(String name, Manifest man) { 2108 2109 String path = name.replace('.', '/') + '/'; 2110 Attributes attr = man.getAttributes(path); 2111 String sealed = null; 2112 if (attr != null) { 2113 sealed = attr.getValue(Name.SEALED); 2114 } 2115 if (sealed == null) { 2116 if ((attr = man.getMainAttributes()) != null) { 2117 sealed = attr.getValue(Name.SEALED); 2118 } 2119 } 2120 return "true".equalsIgnoreCase(sealed); 2121 2122 } 2123 2124 2125 2133 protected InputStream findLoadedResource(String name) { 2134 2135 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); 2136 if (entry != null) { 2137 if (entry.binaryContent != null) 2138 return new ByteArrayInputStream (entry.binaryContent); 2139 } 2140 return (null); 2141 2142 } 2143 2144 2145 2152 protected Class findLoadedClass0(String name) { 2153 2154 ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); 2155 if (entry != null) { 2156 return entry.loadedClass; 2157 } 2158 return (null); 2160 } 2161 2162 2163 2166 protected void refreshPolicy() { 2167 2168 try { 2169 Policy policy = Policy.getPolicy(); 2173 policy.refresh(); 2174 } catch (AccessControlException e) { 2175 } 2178 2179 } 2180 2181 2182 2188 protected boolean filter(String name) { 2189 2190 if (name == null) 2191 return false; 2192 2193 String packageName = null; 2195 int pos = name.lastIndexOf('.'); 2196 if (pos != -1) 2197 packageName = name.substring(0, pos); 2198 else 2199 return false; 2200 2201 for (int i = 0; i < packageTriggers.length; i++) { 2202 if (packageName.startsWith(packageTriggers[i])) 2203 return true; 2204 } 2205 2206 return false; 2207 2208 } 2209 2210 2211 2221 protected boolean validate(String name) { 2222 2223 if (name == null) 2224 return false; 2225 if (name.startsWith("java.")) 2226 return false; 2227 2228 return true; 2229 2230 } 2231 2232 2233 2241 protected boolean validateJarFile(File jarfile) 2242 throws IOException { 2243 2244 if (triggers == null) 2245 return (true); 2246 JarFile jarFile = new JarFile (jarfile); 2247 for (int i = 0; i < triggers.length; i++) { 2248 Class clazz = null; 2249 try { 2250 if (parent != null) { 2251 clazz = parent.loadClass(triggers[i]); 2252 } else { 2253 clazz = Class.forName(triggers[i]); 2254 } 2255 } catch (Throwable t) { 2256 clazz = null; 2257 } 2258 if (clazz == null) 2259 continue; 2260 String name = triggers[i].replace('.', '/') + ".class"; 2261 if (log.isDebugEnabled()) 2262 log.debug(" Checking for " + name); 2263 JarEntry jarEntry = jarFile.getJarEntry(name); 2264 if (jarEntry != null) { 2265 log.info("validateJarFile(" + jarfile + 2266 ") - jar not loaded. See Servlet Spec 2.3, " 2267 + "section 9.7.2. Offending class: " + name); 2268 jarFile.close(); 2269 return (false); 2270 } 2271 } 2272 jarFile.close(); 2273 return (true); 2274 2275 } 2276 2277 2278 2281 protected URL getURL(File file, boolean encoded) 2282 throws MalformedURLException { 2283 2284 File realFile = file; 2285 try { 2286 realFile = realFile.getCanonicalFile(); 2287 } catch (IOException e) { 2288 } 2290 if(encoded) { 2291 return getURI(realFile); 2292 } else { 2293 return realFile.toURL(); 2294 } 2295 2296 } 2297 2298 2299 2302 protected URL getURI(File file) 2303 throws MalformedURLException { 2304 2305 2306 File realFile = file; 2307 try { 2308 realFile = realFile.getCanonicalFile(); 2309 } catch (IOException e) { 2310 } 2312 return realFile.toURI().toURL(); 2313 2314 } 2315 2316 2317 2323 protected static void deleteDir(File dir) { 2324 2325 String files[] = dir.list(); 2326 if (files == null) { 2327 files = new String [0]; 2328 } 2329 for (int i = 0; i < files.length; i++) { 2330 File file = new File (dir, files[i]); 2331 if (file.isDirectory()) { 2332 deleteDir(file); 2333 } else { 2334 file.delete(); 2335 } 2336 } 2337 dir.delete(); 2338 2339 } 2340 2341 2342} 2343 2344 | Popular Tags |