| 1 18 19 package org.apache.tools.ant; 20 21 import java.io.ByteArrayOutputStream ; 22 import java.io.File ; 23 import java.io.FileInputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.io.InputStreamReader ; 27 import java.io.Reader ; 28 import java.lang.reflect.Constructor ; 29 import java.net.MalformedURLException ; 30 import java.net.URL ; 31 import java.util.Collections ; 32 import java.util.Enumeration ; 33 import java.util.HashMap ; 34 import java.util.Hashtable ; 35 import java.util.Map ; 36 import java.util.StringTokenizer ; 37 import java.util.Vector ; 38 import java.util.jar.Attributes ; 39 import java.util.jar.Attributes.Name; 40 import java.util.jar.JarFile ; 41 import java.util.jar.Manifest ; 42 import java.util.zip.ZipEntry ; 43 import java.util.zip.ZipFile ; 44 import org.apache.tools.ant.types.Path; 45 import org.apache.tools.ant.util.CollectionUtils; 46 import org.apache.tools.ant.util.FileUtils; 47 import org.apache.tools.ant.util.JavaEnvUtils; 48 import org.apache.tools.ant.util.LoaderUtils; 49 import org.apache.tools.ant.launch.Locator; 50 51 68 public class AntClassLoader extends ClassLoader implements SubBuildListener { 69 70 private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); 71 72 81 private class ResourceEnumeration implements Enumeration { 82 85 private String resourceName; 86 87 90 private int pathElementsIndex; 91 92 97 private URL nextResource; 98 99 105 ResourceEnumeration(String name) { 106 this.resourceName = name; 107 this.pathElementsIndex = 0; 108 findNextResource(); 109 } 110 111 118 public boolean hasMoreElements() { 119 return (this.nextResource != null); 120 } 121 122 127 public Object nextElement() { 128 URL ret = this.nextResource; 129 findNextResource(); 130 return ret; 131 } 132 133 139 private void findNextResource() { 140 URL url = null; 141 while ((pathElementsIndex < pathComponents.size()) 142 && (url == null)) { 143 try { 144 File pathComponent 145 = (File ) pathComponents.elementAt(pathElementsIndex); 146 url = getResourceURL(pathComponent, this.resourceName); 147 pathElementsIndex++; 148 } catch (BuildException e) { 149 } 152 } 153 this.nextResource = url; 154 } 155 } 156 157 160 private static final int BUFFER_SIZE = 8192; 161 164 private static final int NUMBER_OF_STRINGS = 256; 165 166 170 private Vector pathComponents = new Vector (); 171 172 175 private Project project; 176 177 181 private boolean parentFirst = true; 182 183 188 private Vector systemPackages = new Vector (); 189 190 195 private Vector loaderPackages = new Vector (); 196 197 203 private boolean ignoreBase = false; 204 205 208 private ClassLoader parent = null; 209 210 213 private Hashtable zipFiles = new Hashtable (); 214 215 216 private static Map pathMap = Collections.synchronizedMap(new HashMap ()); 217 218 222 private ClassLoader savedContextLoader = null; 223 226 private boolean isContextLoaderSaved = false; 227 228 237 public AntClassLoader( 238 ClassLoader parent, Project project, Path classpath) { 239 setParent(parent); 240 setClassPath(classpath); 241 setProject(project); 242 } 243 244 247 public AntClassLoader() { 248 setParent(null); 249 } 250 251 262 public AntClassLoader(Project project, Path classpath) { 263 setParent(null); 264 setProject(project); 265 setClassPath(classpath); 266 } 267 268 284 public AntClassLoader(ClassLoader parent, Project project, Path classpath, 285 boolean parentFirst) { 286 this(project, classpath); 287 if (parent != null) { 288 setParent(parent); 289 } 290 setParentFirst(parentFirst); 291 addJavaLibraries(); 292 } 293 294 295 307 public AntClassLoader(Project project, Path classpath, 308 boolean parentFirst) { 309 this(null, project, classpath, parentFirst); 310 } 311 312 325 public AntClassLoader(ClassLoader parent, boolean parentFirst) { 326 setParent(parent); 327 project = null; 328 this.parentFirst = parentFirst; 329 } 330 331 336 public void setProject(Project project) { 337 this.project = project; 338 if (project != null) { 339 project.addBuildListener(this); 340 } 341 } 342 343 350 public void setClassPath(Path classpath) { 351 pathComponents.removeAllElements(); 352 if (classpath != null) { 353 Path actualClasspath = classpath.concatSystemClasspath("ignore"); 354 String [] pathElements = actualClasspath.list(); 355 for (int i = 0; i < pathElements.length; ++i) { 356 try { 357 addPathElement(pathElements[i]); 358 } catch (BuildException e) { 359 } 362 } 363 } 364 } 365 366 372 public void setParent(ClassLoader parent) { 373 if (parent == null) { 374 this.parent = AntClassLoader.class.getClassLoader(); 375 } else { 376 this.parent = parent; 377 } 378 } 379 380 388 public void setParentFirst(boolean parentFirst) { 389 this.parentFirst = parentFirst; 390 } 391 392 393 401 protected void log(String message, int priority) { 402 if (project != null) { 403 project.log(message, priority); 404 } 405 } 409 410 414 public void setThreadContextLoader() { 415 if (isContextLoaderSaved) { 416 throw new BuildException("Context loader has not been reset"); 417 } 418 if (LoaderUtils.isContextLoaderAvailable()) { 419 savedContextLoader = LoaderUtils.getContextClassLoader(); 420 ClassLoader loader = this; 421 if (project != null 422 && "only".equals(project.getProperty("build.sysclasspath"))) { 423 loader = this.getClass().getClassLoader(); 424 } 425 LoaderUtils.setContextClassLoader(loader); 426 isContextLoaderSaved = true; 427 } 428 } 429 430 433 public void resetThreadContextLoader() { 434 if (LoaderUtils.isContextLoaderAvailable() 435 && isContextLoaderSaved) { 436 LoaderUtils.setContextClassLoader(savedContextLoader); 437 savedContextLoader = null; 438 isContextLoaderSaved = false; 439 } 440 } 441 442 443 452 public void addPathElement(String pathElement) throws BuildException { 453 File pathComponent 454 = project != null ? project.resolveFile(pathElement) 455 : new File (pathElement); 456 try { 457 addPathFile(pathComponent); 458 } catch (IOException e) { 459 throw new BuildException(e); 460 } 461 } 462 463 473 protected void addPathFile(File pathComponent) throws IOException { 474 pathComponents.addElement(pathComponent); 475 if (pathComponent.isDirectory()) { 476 return; 477 } 478 479 String absPathPlusTimeAndLength = 480 pathComponent.getAbsolutePath() + pathComponent.lastModified() + "-" 481 + pathComponent.length(); 482 String classpath = (String ) pathMap.get(absPathPlusTimeAndLength); 483 if (classpath == null) { 484 ZipFile jarFile = null; 485 InputStream manifestStream = null; 486 try { 487 jarFile = new ZipFile (pathComponent); 488 manifestStream 489 = jarFile.getInputStream(new ZipEntry ("META-INF/MANIFEST.MF")); 490 491 if (manifestStream == null) { 492 return; 493 } 494 Reader manifestReader 495 = new InputStreamReader (manifestStream, "UTF-8"); 496 org.apache.tools.ant.taskdefs.Manifest manifest 497 = new org.apache.tools.ant.taskdefs.Manifest(manifestReader); 498 classpath 499 = manifest.getMainSection().getAttributeValue("Class-Path"); 500 501 } catch (org.apache.tools.ant.taskdefs.ManifestException e) { 502 } finally { 504 if (manifestStream != null) { 505 manifestStream.close(); 506 } 507 if (jarFile != null) { 508 jarFile.close(); 509 } 510 } 511 if (classpath == null) { 512 classpath = ""; 513 } 514 pathMap.put(absPathPlusTimeAndLength, classpath); 515 } 516 517 if (!"".equals(classpath)) { 518 URL baseURL = FILE_UTILS.getFileURL(pathComponent); 519 StringTokenizer st = new StringTokenizer (classpath); 520 while (st.hasMoreTokens()) { 521 String classpathElement = st.nextToken(); 522 URL libraryURL = new URL (baseURL, classpathElement); 523 if (!libraryURL.getProtocol().equals("file")) { 524 log("Skipping jar library " + classpathElement 525 + " since only relative URLs are supported by this" 526 + " loader", Project.MSG_VERBOSE); 527 continue; 528 } 529 String decodedPath = Locator.decodeUri(libraryURL.getFile()); 530 File libraryFile = new File (decodedPath); 531 if (libraryFile.exists() && !isInPath(libraryFile)) { 532 addPathFile(libraryFile); 533 } 534 } 535 } 536 } 537 538 544 public String getClasspath() { 545 StringBuffer sb = new StringBuffer (); 546 boolean firstPass = true; 547 Enumeration componentEnum = pathComponents.elements(); 548 while (componentEnum.hasMoreElements()) { 549 if (!firstPass) { 550 sb.append(System.getProperty("path.separator")); 551 } else { 552 firstPass = false; 553 } 554 sb.append(((File ) componentEnum.nextElement()).getAbsolutePath()); 555 } 556 return sb.toString(); 557 } 558 559 568 public synchronized void setIsolated(boolean isolated) { 569 ignoreBase = isolated; 570 } 571 572 582 public static void initializeClass(Class theClass) { 583 588 final Constructor [] cons = theClass.getDeclaredConstructors(); 589 if (cons != null) { 591 if (cons.length > 0 && cons[0] != null) { 592 final String [] strs = new String [NUMBER_OF_STRINGS]; 593 try { 594 cons[0].newInstance((Object []) strs); 595 } catch (Exception e) { 598 } 611 } 612 } 613 } 614 615 624 public void addSystemPackageRoot(String packageRoot) { 625 systemPackages.addElement(packageRoot 626 + (packageRoot.endsWith(".") ? "" : ".")); 627 } 628 629 638 public void addLoaderPackageRoot(String packageRoot) { 639 loaderPackages.addElement(packageRoot 640 + (packageRoot.endsWith(".") ? "" : ".")); 641 } 642 643 658 public Class forceLoadClass(String classname) 659 throws ClassNotFoundException { 660 log("force loading " + classname, Project.MSG_DEBUG); 661 662 Class theClass = findLoadedClass(classname); 663 664 if (theClass == null) { 665 theClass = findClass(classname); 666 } 667 668 return theClass; 669 } 670 671 687 public Class forceLoadSystemClass(String classname) 688 throws ClassNotFoundException { 689 log("force system loading " + classname, Project.MSG_DEBUG); 690 691 Class theClass = findLoadedClass(classname); 692 693 if (theClass == null) { 694 theClass = findBaseClass(classname); 695 } 696 697 return theClass; 698 } 699 700 709 public InputStream getResourceAsStream(String name) { 710 711 InputStream resourceStream = null; 712 if (isParentFirst(name)) { 713 resourceStream = loadBaseResource(name); 714 if (resourceStream != null) { 715 log("ResourceStream for " + name 716 + " loaded from parent loader", Project.MSG_DEBUG); 717 718 } else { 719 resourceStream = loadResource(name); 720 if (resourceStream != null) { 721 log("ResourceStream for " + name 722 + " loaded from ant loader", Project.MSG_DEBUG); 723 } 724 } 725 } else { 726 resourceStream = loadResource(name); 727 if (resourceStream != null) { 728 log("ResourceStream for " + name 729 + " loaded from ant loader", Project.MSG_DEBUG); 730 731 } else { 732 resourceStream = loadBaseResource(name); 733 if (resourceStream != null) { 734 log("ResourceStream for " + name 735 + " loaded from parent loader", Project.MSG_DEBUG); 736 } 737 } 738 } 739 740 if (resourceStream == null) { 741 log("Couldn't load ResourceStream for " + name, 742 Project.MSG_DEBUG); 743 } 744 745 return resourceStream; 746 } 747 748 757 private InputStream loadResource(String name) { 758 InputStream stream = null; 761 762 Enumeration e = pathComponents.elements(); 763 while (e.hasMoreElements() && stream == null) { 764 File pathComponent = (File ) e.nextElement(); 765 stream = getResourceStream(pathComponent, name); 766 } 767 return stream; 768 } 769 770 780 private InputStream loadBaseResource(String name) { 781 if (parent == null) { 782 return getSystemResourceAsStream(name); 783 } else { 784 return parent.getResourceAsStream(name); 785 } 786 } 787 788 800 private InputStream getResourceStream(File file, String resourceName) { 801 try { 802 if (!file.exists()) { 803 return null; 804 } 805 806 if (file.isDirectory()) { 807 File resource = new File (file, resourceName); 808 809 if (resource.exists()) { 810 return new FileInputStream (resource); 811 } 812 } else { 813 ZipFile zipFile = (ZipFile ) zipFiles.get(file); 815 if (zipFile == null) { 816 zipFile = new ZipFile (file); 817 zipFiles.put(file, zipFile); 818 } 819 ZipEntry entry = zipFile.getEntry(resourceName); 820 if (entry != null) { 821 return zipFile.getInputStream(entry); 822 } 823 } 824 } catch (Exception e) { 825 log("Ignoring Exception " + e.getClass().getName() 826 + ": " + e.getMessage() + " reading resource " + resourceName 827 + " from " + file, Project.MSG_VERBOSE); 828 } 829 830 return null; 831 } 832 833 &n
|