Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 1,304   Methods: 50
NCLOC: 562   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
AntClassLoader.java 64.3% 72.5% 78% 70.8%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant;
 55   
 
 56   
 import java.io.ByteArrayOutputStream;
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.IOException;
 60   
 import java.io.InputStream;
 61   
 import java.lang.reflect.Constructor;
 62   
 import java.lang.reflect.InvocationTargetException;
 63   
 import java.lang.reflect.Method;
 64   
 import java.net.MalformedURLException;
 65   
 import java.net.URL;
 66   
 import java.util.Enumeration;
 67   
 import java.util.Hashtable;
 68   
 import java.util.Vector;
 69   
 import java.util.zip.ZipEntry;
 70   
 import java.util.zip.ZipFile;
 71   
 import org.apache.tools.ant.types.Path;
 72   
 import org.apache.tools.ant.util.JavaEnvUtils;
 73   
 import org.apache.tools.ant.util.LoaderUtils;
 74   
 
 75   
 /**
 76   
  * Used to load classes within ant with a different claspath from
 77   
  * that used to start ant. Note that it is possible to force a class
 78   
  * into this loader even when that class is on the system classpath by
 79   
  * using the forceLoadClass method. Any subsequent classes loaded by that
 80   
  * class will then use this loader rather than the system class loader.
 81   
  *
 82   
  * @author Conor MacNeill
 83   
  * @author <a href="mailto:Jesse.Glick@netbeans.com">Jesse Glick</a>
 84   
  * @author Magesh Umasankar
 85   
  */
 86   
 public class AntClassLoader extends ClassLoader implements BuildListener {
 87   
 
 88   
     /**
 89   
      * An enumeration of all resources of a given name found within the
 90   
      * classpath of this class loader. This enumeration is used by the
 91   
      * ClassLoader.findResources method, which is in
 92   
      * turn used by the ClassLoader.getResources method.
 93   
      *
 94   
      * @see AntClassLoader#findResources(String)
 95   
      * @see java.lang.ClassLoader#getResources(String)
 96   
      * @author <a href="mailto:hermand@alumni.grinnell.edu">David A. Herman</a>
 97   
      */
 98   
     private class ResourceEnumeration implements Enumeration {
 99   
         /**
 100   
          * The name of the resource being searched for.
 101   
          */
 102   
         private String resourceName;
 103   
 
 104   
         /**
 105   
          * The index of the next classpath element to search.
 106   
          */
 107   
         private int pathElementsIndex;
 108   
 
 109   
         /**
 110   
          * The URL of the next resource to return in the enumeration. If this
 111   
          * field is <code>null</code> then the enumeration has been completed,
 112   
          * i.e., there are no more elements to return.
 113   
          */
 114   
         private URL nextResource;
 115   
 
 116   
         /**
 117   
          * Constructs a new enumeration of resources of the given name found
 118   
          * within this class loader's classpath.
 119   
          *
 120   
          * @param name the name of the resource to search for.
 121   
          */
 122  0
         ResourceEnumeration(String name) {
 123  0
             this.resourceName = name;
 124  0
             this.pathElementsIndex = 0;
 125  0
             findNextResource();
 126   
         }
 127   
 
 128   
         /**
 129   
          * Indicates whether there are more elements in the enumeration to
 130   
          * return.
 131   
          *
 132   
          * @return <code>true</code> if there are more elements in the
 133   
          *         enumeration; <code>false</code> otherwise.
 134   
          */
 135  0
         public boolean hasMoreElements() {
 136  0
             return (this.nextResource != null);
 137   
         }
 138   
 
 139   
         /**
 140   
          * Returns the next resource in the enumeration.
 141   
          *
 142   
          * @return the next resource in the enumeration
 143   
          */
 144  0
         public Object nextElement() {
 145  0
             URL ret = this.nextResource;
 146  0
             findNextResource();
 147  0
             return ret;
 148   
         }
 149   
 
 150   
         /**
 151   
          * Locates the next resource of the correct name in the classpath and
 152   
          * sets <code>nextResource</code> to the URL of that resource. If no
 153   
          * more resources can be found, <code>nextResource</code> is set to
 154   
          * <code>null</code>.
 155   
          */
 156  0
         private void findNextResource() {
 157  0
             URL url = null;
 158  0
             while ((pathElementsIndex < pathComponents.size()) &&
 159   
                    (url == null)) {
 160  0
                 try {
 161  0
                     File pathComponent
 162   
                         = (File) pathComponents.elementAt(pathElementsIndex);
 163  0
                     url = getResourceURL(pathComponent, this.resourceName);
 164  0
                     pathElementsIndex++;
 165   
                 } catch (BuildException e) {
 166   
                     // ignore path elements which are not valid relative to the
 167   
                     // project
 168   
                 }
 169   
             }
 170  0
             this.nextResource = url;
 171   
         }
 172   
     }
 173   
 
 174   
     /**
 175   
      * The size of buffers to be used in this classloader.
 176   
      */
 177   
     private static final int BUFFER_SIZE = 8192;
 178   
 
 179   
     /**
 180   
      * The components of the classpath that the classloader searches
 181   
      * for classes.
 182   
      */
 183   
     private Vector pathComponents  = new Vector();
 184   
 
 185   
     /**
 186   
      * The project to which this class loader belongs.
 187   
      */
 188   
     private Project project;
 189   
 
 190   
     /**
 191   
      * Indicates whether the parent class loader should be
 192   
      * consulted before trying to load with this class loader.
 193   
      */
 194   
     private boolean parentFirst = true;
 195   
 
 196   
     /**
 197   
      * These are the package roots that are to be loaded by the parent class
 198   
      * loader regardless of whether the parent class loader is being searched
 199   
      * first or not.
 200   
      */
 201   
     private Vector systemPackages = new Vector();
 202   
 
 203   
     /**
 204   
      * These are the package roots that are to be loaded by this class loader
 205   
      * regardless of whether the parent class loader is being searched first
 206   
      * or not.
 207   
      */
 208   
     private Vector loaderPackages = new Vector();
 209   
 
 210   
     /**
 211   
      * Whether or not this classloader will ignore the base
 212   
      * classloader if it can't find a class.
 213   
      *
 214   
      * @see #setIsolated(boolean)
 215   
      */
 216   
     private boolean ignoreBase = false;
 217   
 
 218   
     /**
 219   
      * The parent class loader, if one is given or can be determined.
 220   
      */
 221   
     private ClassLoader parent = null;
 222   
 
 223   
     /**
 224   
      * A hashtable of zip files opened by the classloader (File to ZipFile).
 225   
      */
 226   
     private Hashtable zipFiles = new Hashtable();
 227   
 
 228   
     /**
 229   
      * The context loader saved when setting the thread's current
 230   
      * context loader.
 231   
      */
 232   
     private ClassLoader savedContextLoader = null;
 233   
     /**
 234   
      * Whether or not the context loader is currently saved.
 235   
      */
 236   
     private boolean isContextLoaderSaved = false;
 237   
 
 238   
     /**
 239   
      * Reflection method reference for getProtectionDomain;
 240   
      * used to avoid 1.1-compatibility problems.
 241   
      */
 242   
     private static Method getProtectionDomain = null;
 243   
 
 244   
     /**
 245   
      * Reflection method reference for defineClassProtectionDomain;
 246   
      * used to avoid 1.1-compatibility problems.
 247   
      */
 248   
     private static Method defineClassProtectionDomain = null;
 249   
 
 250   
 
 251   
     // Set up the reflection-based Java2 methods if possible
 252   
     static {
 253  1
         try {
 254  1
             getProtectionDomain
 255   
                 = Class.class.getMethod("getProtectionDomain", new Class[0]);
 256  1
             Class protectionDomain
 257   
                 = Class.forName("java.security.ProtectionDomain");
 258  1
             Class[] args = new Class[] {String.class, byte[].class,
 259   
                 Integer.TYPE, Integer.TYPE, protectionDomain};
 260  1
             defineClassProtectionDomain
 261   
                 = ClassLoader.class.getDeclaredMethod("defineClass", args);
 262   
         } catch (Exception e) {
 263   
             // ignore failure to get access to 1.2+ methods
 264   
         }
 265   
     }
 266   
 
 267   
 
 268   
     /**
 269   
      * Create an Ant Class Loader 
 270   
      */
 271  254
     public AntClassLoader() {
 272  254
         setParent(null);
 273   
     }
 274   
 
 275   
     /**
 276   
      * Creates a classloader for the given project using the classpath given.
 277   
      *
 278   
      * @param project The project to which this classloader is to belong.
 279   
      *                Must not be <code>null</code>.
 280   
      * @param classpath The classpath to use to load the classes.  This
 281   
      *                is combined with the system classpath in a manner
 282   
      *                determined by the value of ${build.sysclasspath}.
 283   
      *                May be <code>null</code>, in which case no path
 284   
      *                elements are set up to start with.
 285   
      */
 286  1
     public AntClassLoader(Project project, Path classpath) {
 287  1
         setParent(null);
 288  1
         setProject(project);
 289  1
         setClassPath(classpath);
 290   
     }
 291   
 
 292   
     /**
 293   
      * Creates a classloader for the given project using the classpath given.
 294   
      *
 295   
      * @param parent The parent classloader to which unsatisfied loading
 296   
      *               attempts are delegated. May be <code>null</code>,
 297   
      *               in which case the classloader which loaded this
 298   
      *               class is used as the parent.
 299   
      * @param project The project to which this classloader is to belong.
 300   
      *                Must not be <code>null</code>.
 301   
      * @param classpath the classpath to use to load the classes.
 302   
      *                  May be <code>null</code>, in which case no path
 303   
      *                  elements are set up to start with.
 304   
      * @param parentFirst If <code>true</code>, indicates that the parent
 305   
      *                    classloader should be consulted  before trying to
 306   
      *                    load the a class through this loader.
 307   
      */
 308  0
     public AntClassLoader(ClassLoader parent, Project project, Path classpath,
 309   
                           boolean parentFirst) {
 310  0
         this(project, classpath);
 311  0
         if (parent != null) {
 312  0
             setParent(parent);
 313   
         }
 314  0
         setParentFirst(parentFirst);
 315  0
         addJavaLibraries();
 316   
     }
 317   
 
 318   
 
 319   
     /**
 320   
      * Creates a classloader for the given project using the classpath given.
 321   
      *
 322   
      * @param project The project to which this classloader is to belong.
 323   
      *                Must not be <code>null</code>.
 324   
      * @param classpath The classpath to use to load the classes. May be
 325   
      *                  <code>null</code>, in which case no path
 326   
      *                  elements are set up to start with.
 327   
      * @param parentFirst If <code>true</code>, indicates that the parent
 328   
      *                    classloader should be consulted before trying to
 329   
      *                    load the a class through this loader.
 330   
      */
 331  0
     public AntClassLoader(Project project, Path classpath,
 332   
                           boolean parentFirst) {
 333  0
         this(null, project, classpath, parentFirst);
 334   
     }
 335   
 
 336   
     /**
 337   
      * Creates an empty class loader. The classloader should be configured
 338   
      * with path elements to specify where the loader is to look for
 339   
      * classes.
 340   
      *
 341   
      * @param parent The parent classloader to which unsatisfied loading
 342   
      *               attempts are delegated. May be <code>null</code>,
 343   
      *               in which case the classloader which loaded this
 344   
      *               class is used as the parent.
 345   
      * @param parentFirst If <code>true</code>, indicates that the parent
 346   
      *                    classloader should be consulted before trying to
 347   
      *                    load the a class through this loader.
 348   
      */
 349  0
     public AntClassLoader(ClassLoader parent, boolean parentFirst) {
 350  0
         setParent(parent);
 351  0
         project = null;
 352  0
         this.parentFirst = parentFirst;
 353   
     }
 354   
 
 355   
     /**
 356   
      * Set the project associated with this class loader 
 357   
      *
 358   
      * @param project the project instance
 359   
      */
 360  255
     public void setProject(Project project) {
 361  255
         this.project = project;
 362  255
         if (project != null) {
 363  255
             project.addBuildListener(this);
 364   
         }
 365   
     }
 366   
 
 367   
     /**
 368   
      * Set the classpath to search for classes to load. This should not be
 369   
      * changed once the classloader starts to server classes 
 370   
      *
 371   
      * @param classpath the serahc classpath consisting of directories and
 372   
      *        jar/zip files.
 373   
      */
 374  255
     public void setClassPath(Path classpath) {
 375  255
         pathComponents.removeAllElements();
 376  255
         if (classpath != null) {
 377  247
             Path actualClasspath = classpath.concatSystemClasspath("ignore");
 378  247
             String[] pathElements = actualClasspath.list();
 379  247
             for (int i = 0; i < pathElements.length; ++i) {
 380  4601
                 try {
 381  4601
                     addPathElement(pathElements[i]);
 382   
                 } catch (BuildException e) {
 383   
                     // ignore path elements which are invalid
 384   
                     // relative to the project
 385   
                 }
 386   
             }
 387   
         }
 388   
     }
 389   
 
 390   
     /**
 391   
      * Set the parent for this class loader. This is the class loader to which
 392   
      * this class loader will delegate to load classes
 393   
      *
 394   
      * @param parent the parent class loader.
 395   
      */
 396  261
     public void setParent(ClassLoader parent) {
 397  261
         if (parent == null) {
 398  261
             this.parent = AntClassLoader.class.getClassLoader();
 399   
         } else {
 400  0
             this.parent = parent;
 401   
         }
 402   
     }
 403   
 
 404   
     /**
 405   
      * Control whether class lookup is delegated to the parent loader first
 406   
      * or after this loader. Use with extreme caution. Setting this to 
 407   
      * false violates the class loader hierarchy and can lead to Linkage errors
 408   
      *
 409   
      * @param parentFirst if true, delegate initial class search to the parent
 410   
      *                    classloader.
 411   
      */
 412  144
     public void setParentFirst(boolean parentFirst) {
 413  144
         this.parentFirst = parentFirst;
 414   
     }
 415   
 
 416   
 
 417   
     /**
 418   
      * Logs a message through the project object if one has been provided.
 419   
      *
 420   
      * @param message The message to log.
 421   
      *                Should not be <code>null</code>.
 422   
      *
 423   
      * @param priority The logging priority of the message.
 424   
      */
 425  7966
     protected void log(String message, int priority) {
 426  7966
         if (project != null) {
 427  7965
             project.log(message, priority);
 428   
         }
 429   
 //         else {
 430   
 //             System.out.println(message);
 431   
 //         }
 432   
     }
 433   
 
 434   
     /**
 435   
      * Sets the current thread's context loader to this classloader, storing
 436   
      * the current loader value for later resetting.
 437   
      */
 438  142
     public void setThreadContextLoader() {
 439  142
         if (isContextLoaderSaved) {
 440  0
             throw new BuildException("Context loader has not been reset");
 441   
         }
 442  142
         if (LoaderUtils.isContextLoaderAvailable()) {
 443  142
             savedContextLoader = LoaderUtils.getContextClassLoader();
 444  142
             ClassLoader loader = this;
 445  142
             if (project != null
 446   
                 && "only".equals(project.getProperty("build.sysclasspath"))) {
 447  0
                 loader = this.getClass().getClassLoader();
 448   
             }
 449  142
             LoaderUtils.setContextClassLoader(loader);
 450  142
             isContextLoaderSaved = true;
 451   
         }
 452   
     }
 453   
 
 454   
     /**
 455   
      * Resets the current thread's context loader to its original value.
 456   
      */
 457  142
     public void resetThreadContextLoader() {
 458  142
         if (LoaderUtils.isContextLoaderAvailable()
 459   
             && isContextLoaderSaved) {
 460  142
             LoaderUtils.setContextClassLoader(savedContextLoader);
 461  142
             savedContextLoader = null;
 462  142
             isContextLoaderSaved = false;
 463   
         }
 464   
     }
 465   
 
 466   
 
 467   
     /**
 468   
      * Adds an element to the classpath to be searched.
 469   
      *
 470   
      * @param pathElement The path element to add. Must not be
 471   
      *                    <code>null</code>.
 472   
      *
 473   
      * @exception BuildException if the given path element cannot be resolved
 474   
      *                           against the project.
 475   
      */
 476  4601
     public void addPathElement(String pathElement) throws BuildException {
 477  4601
         File pathComponent
 478   
             = project != null ? project.resolveFile(pathElement)
 479   
                               : new File(pathElement);
 480  4601
         try {
 481  4601
             addPathFile(pathComponent);
 482   
         } catch (IOException e) {
 483  0
             throw new BuildException(e);
 484   
         }
 485   
     }
 486   
     
 487   
     /**
 488   
      * Add a file to the path
 489   
      *
 490   
      * @param pathComponent the file which is to be added to the path for
 491   
      *                      this class loader
 492   
      *
 493   
      * @throws IOException if data needed from the file cannot be read.
 494   
      */
 495  4601
     protected void addPathFile(File pathComponent) throws IOException { 
 496  4601
         pathComponents.addElement(pathComponent);
 497   
     }
 498   
 
 499   
     /**
 500   
      * Returns the classpath this classloader will consult.
 501   
      *
 502   
      * @return the classpath used for this classloader, with elements
 503   
      *         separated by the path separator for the system.
 504   
      */
 505  136
     public String getClasspath() {
 506  136
         StringBuffer sb = new StringBuffer();
 507  136
         boolean firstPass = true;
 508  136
         Enumeration enum = pathComponents.elements();
 509  136
         while (enum.hasMoreElements()) {
 510  952
             if (!firstPass) {
 511  816
                 sb.append(System.getProperty("path.separator"));
 512   
             } else {
 513  136
                 firstPass = false;
 514   
             }
 515  952
             sb.append(((File) enum.nextElement()).getAbsolutePath());
 516   
         }
 517  136
         return sb.toString();
 518   
     }
 519   
 
 520   
     /**
 521   
      * Sets whether this classloader should run in isolated mode. In
 522   
      * isolated mode, classes not found on the given classpath will
 523   
      * not be referred to the parent class loader but will cause a
 524   
      * ClassNotFoundException.
 525   
      *
 526   
      * @param isolated Whether or not this classloader should run in
 527   
      *                 isolated mode.
 528   
      */
 529  6
     public void setIsolated(boolean isolated) {
 530  6
         ignoreBase = isolated;
 531   
     }
 532   
 
 533   
     /**
 534   
      * Forces initialization of a class in a JDK 1.1 compatible, albeit hacky
 535   
      * way.
 536   
      *
 537   
      * @param theClass The class to initialize.
 538   
      *                 Must not be <code>null</code>.
 539   
      */
 540  219
     public static void initializeClass(Class theClass) {
 541   
         // ***HACK*** We ask the VM to create an instance
 542   
         // by voluntarily providing illegal arguments to force
 543   
         // the VM to run the class' static initializer, while
 544   
         // at the same time not running a valid constructor.
 545   
 
 546  219
         final Constructor[] cons = theClass.getDeclaredConstructors();
 547   
         //At least one constructor is guaranteed to be there, but check anyway.
 548  219
         if (cons != null) {
 549  219
             if (cons.length > 0 && cons[0] != null) {
 550  211
                 final String[] strs = new String[256];
 551  211
                 try {
 552  211
                     cons[0].newInstance(strs);
 553   
                     // Expecting an exception to be thrown by this call:
 554   
                     // IllegalArgumentException: wrong number of Arguments
 555   
                 } catch (Throwable t) {
 556   
                     // Ignore - we are interested only in the side
 557   
                     // effect - that of getting the static initializers
 558   
                     // invoked.  As we do not want to call a valid
 559   
                     // constructor to get this side effect, an
 560   
                     // attempt is made to call a hopefully
 561   
                     // invalid constructor - come on, nobody
 562   
                     // would have a constructor that takes in
 563   
                     // 256 String arguments ;-)
 564   
                     // (In fact, they can't - according to JVM spec
 565   
                     // section 4.10, the number of method parameters is limited
 566   
                     // to 255 by the definition of a method descriptor.
 567   
                     // Constructors count as methods here.)
 568   
                 }
 569   
             }
 570   
         }
 571   
     }
 572   
 
 573   
     /**
 574   
      * Adds a package root to the list of packages which must be loaded on the
 575   
      * parent loader.
 576   
      *
 577   
      * All subpackages are also included.
 578   
      *
 579   
      * @param packageRoot The root of all packages to be included.
 580   
      *                    Should not be <code>null</code>.
 581   
      */
 582  3334
     public void addSystemPackageRoot(String packageRoot) {
 583  3334
         systemPackages.addElement(packageRoot
 584   
                                   + (packageRoot.endsWith(".") ? "" : "."));
 585   
     }
 586   
 
 587   
     /**
 588   
      * Adds a package root to the list of packages which must be loaded using
 589   
      * this loader.
 590   
      *
 591   
      * All subpackages are also included.
 592   
      *
 593   
      * @param packageRoot The root of all packages to be included.
 594   
      *                    Should not be <code>null</code>.
 595   
      */
 596  0
     public void addLoaderPackageRoot(String packageRoot) {
 597  0
         loaderPackages.addElement(packageRoot
 598   
                                   + (packageRoot.endsWith(".") ? "" : "."));
 599   
     }
 600   
 
 601   
     /**
 602   
      * Loads a class through this class loader even if that class is available
 603   
      * on the parent classpath.
 604   
      *
 605   
      * This ensures that any classes which are loaded by the returned class
 606   
      * will use this classloader.
 607   
      *
 608   
      * @param classname The name of the class to be loaded.
 609   
      *                  Must not be <code>null</code>.
 610   
      *
 611   
      * @return the required Class object
 612   
      *
 613   
      * @exception ClassNotFoundException if the requested class does not exist
 614   
      *                                   on this loader's classpath.
 615   
      */
 616  6
     public Class forceLoadClass(String classname)
 617   
          throws ClassNotFoundException {
 618  6
         log("force loading " + classname, Project.MSG_DEBUG);
 619   
 
 620  6
         Class theClass = findLoadedClass(classname);
 621   
 
 622  6
         if (theClass == null) {
 623  6
             theClass = findClass(classname);
 624   
         }
 625   
 
 626  6
         return theClass;
 627   
     }
 628   
 
 629   
     /**
 630   
      * Loads a class through this class loader but defer to the parent class
 631   
      * loader.
 632   
      *
 633   
      * This ensures that instances of the returned class will be compatible
 634   
      * with instances which which have already been loaded on the parent
 635   
      * loader.
 636   
      *
 637   
      * @param classname The name of the class to be loaded.
 638   
      *                  Must not be <code>null</code>.
 639   
      *
 640   
      * @return the required Class object
 641   
      *
 642   
      * @exception ClassNotFoundException if the requested class does not exist
 643   
      * on this loader's classpath.
 644   
      */
 645  22
     public Class forceLoadSystemClass(String classname)
 646   
          throws ClassNotFoundException {
 647  22
         log("force system loading " + classname, Project.MSG_DEBUG);
 648   
 
 649  22
         Class theClass = findLoadedClass(classname);
 650   
 
 651  22
         if (theClass == null) {
 652  22
             theClass = findBaseClass(classname);
 653   
         }
 654   
 
 655  22
         return theClass;
 656   
     }
 657   
 
 658   
     /**
 659   
      * Returns a stream to read the requested resource name.
 660   
      *
 661   
      * @param name The name of the resource for which a stream is required.
 662   
      *             Must not be <code>null</code>.
 663   
      *
 664   
      * @return a stream to the required resource or <code>null</code> if the
 665   
      *         resource cannot be found on the loader's classpath.
 666   
      */
 667  1321
     public InputStream getResourceAsStream(String name) {
 668   
 
 669  1321
         InputStream resourceStream = null;
 670  1321
         if (isParentFirst(name)) {
 671  6
             resourceStream = loadBaseResource(name);
 672  6
             if (resourceStream != null) {
 673  0
                 log("ResourceStream for " + name
 674   
                     + " loaded from parent loader", Project.MSG_DEBUG);
 675   
 
 676   
             } else {
 677  6
                 resourceStream = loadResource(name);
 678  6
                 if (resourceStream != null) {
 679  6
                     log("ResourceStream for " + name
 680   
                         + " loaded from ant loader", Project.MSG_DEBUG);
 681   
                 }
 682   
             }
 683   
         } else {
 684  1315
             resourceStream = loadResource(name);
 685  1315
             if (resourceStream != null) {
 686  1
                 log("ResourceStream for " + name
 687   
                     + " loaded from ant loader", Project.MSG_DEBUG);
 688   
 
 689   
             } else {
 690  1314
                 resourceStream = loadBaseResource(name);
 691  1314
                 if (resourceStream != null) {
 692  740
                     log("ResourceStream for " + name
 693   
                         + " loaded from parent loader", Project.MSG_DEBUG);
 694   
                 }
 695   
             }
 696   
         }
 697   
 
 698  1321
         if (resourceStream == null) {
 699  574
             log("Couldn't load ResourceStream for " + name,
 700   
                 Project.MSG_DEBUG);
 701   
         }
 702   
 
 703  1321
         return resourceStream;
 704   
     }
 705   
 
 706   
     /**
 707   
      * Returns a stream to read the requested resource name from this loader.
 708   
      *
 709   
      * @param name The name of the resource for which a stream is required.
 710   
      *             Must not be <code>null</code>.
 711   
      *
 712   
      * @return a stream to the required resource or <code>null</code> if
 713   
      *         the resource cannot be found on the loader's classpath.
 714   
      */
 715  1321
     private InputStream loadResource(String name) {
 716   
         // we need to search the components of the path to see if we can
 717   
         // find the class we want.
 718  1321
         InputStream stream = null;
 719   
 
 720  1321
         Enumeration e = pathComponents.elements();
 721  1321
         while (e.hasMoreElements() && stream == null) {
 722  9207
             File pathComponent = (File) e.nextElement();
 723  9207
             stream = getResourceStream(pathComponent, name);
 724   
         }
 725  1321
         return stream;
 726   
     }
 727   
 
 728   
     /**
 729   
      * Finds a system resource (which should be loaded from the parent
 730   
      * classloader).
 731   
      *
 732   
      * @param name The name of the system resource to load.
 733   
      *             Must not be <code>null</code>.
 734   
      *
 735   
      * @return a stream to the named resource, or <code>null</code> if
 736   
      *         the resource cannot be found.
 737   
      */
 738  1320
     private InputStream loadBaseResource(String name) {
 739  1320
         if (parent == null) {
 740  0
             return getSystemResourceAsStream(name);
 741   
         } else {
 742  1320
             return parent.getResourceAsStream(name);
 743   
         }
 744   
     }
 745   
 
 746   
     /**
 747   
      * Returns an inputstream to a given resource in the given file which may
 748   
      * either be a directory or a zip file.
 749   
      *
 750   
      * @param file the file (directory or jar) in which to search for the
 751   
      *             resource. Must not be <code>null</code>.
 752   
      * @param resourceName The name of the resource for which a stream is
 753   
      *                     required. Must not be <code>null</code>.
 754   
      *
 755   
      * @return a stream to the required resource or <code>null</code> if
 756   
      *         the resource cannot be found in the given file.
 757   
      */
 758  20218
     private InputStream getResourceStream(File file, String resourceName) {
 759  20218
         try {
 760  20218
             if (!file.exists()) {
 761  0
                 return null;
 762   
             }
 763   
 
 764  20218
             if (file.isDirectory()) {
 765  11898
                 File resource = new File(file, resourceName);
 766   
 
 767  11898
                 if (resource.exists()) {
 768  513
                     return new FileInputStream(resource);
 769   
                 }
 770   
             } else {
 771   
                 // is the zip file in the cache
 772  8320
                 ZipFile zipFile = (ZipFile) zipFiles.get(file);
 773  8320
                 if (zipFile == null) {
 774  400
                     zipFile = new ZipFile(file);
 775  400
                     zipFiles.put(file, zipFile);
 776   
                 }
 777  8320
                 ZipEntry entry = zipFile.getEntry(resourceName);
 778  8320
                 if (entry != null) {
 779  2
                     return zipFile.getInputStream(entry);
 780   
                 }
 781   
             }
 782   
         } catch (Exception e) {
 783  0
             log("Ignoring Exception " + e.getClass().getName()
 784   
                 + ": " + e.getMessage() + " reading resource " + resourceName
 785   
                 + " from " + file, Project.MSG_VERBOSE);
 786   
         }
 787   
 
 788  19703
         return null;
 789   
     }
 790   
 
 791   
     /**
 792   
      * Tests whether or not the parent classloader should be checked for
 793   
      * a resource before this one. If the resource matches both the
 794   
      * "use parent classloader first" and the "use this classloader first"
 795   
      * lists, the latter takes priority.
 796   
      *
 797   
      * @param resourceName The name of the resource to check.
 798   
      *                     Must not be <code>null</code>.
 799   
      *
 800   
      * @return whether or not the parent classloader should be checked for a
 801   
      *         resource before this one is.
 802   
      */
 803  5500
     private boolean isParentFirst(String resourceName) {
 804   
         // default to the global setting and then see
 805   
         // if this class belongs to a package which has been
 806   
         // designated to use a specific loader first
 807   
         // (this one or the parent one)
 808   
 
 809   
         // XXX - shouldn't this always return false in isolated mode?
 810   
 
 811  5500
         boolean useParentFirst = parentFirst;
 812   
 
 813  5500
         for (Enumeration e = systemPackages.elements(); e.hasMoreElements();) {
 814  119228
             String packageName = (String) e.nextElement();
 815  119228
             if (resourceName.startsWith(packageName)) {
 816  2651
                 useParentFirst = true;
 817  2651
                 break;
 818   
             }
 819   
         }
 820   
 
 821  5500
         for (Enumeration e = loaderPackages.elements(); e.hasMoreElements();) {
 822  0
             String packageName = (String) e.nextElement();
 823  0
             if (resourceName.startsWith(packageName)) {
 824  0
                 useParentFirst = false;
 825  0
                 break;
 826   
             }
 827   
         }
 828   
 
 829  5500
         return useParentFirst;
 830   
     }
 831   
 
 832   
     /**
 833   
      * Finds the resource with the given name. A resource is
 834   
      * some data (images, audio, text, etc) that can be accessed by class
 835   
      * code in a way that is independent of the location of the code.
 836   
      *
 837   
      * @param name The name of the resource for which a stream is required.
 838   
      *             Must not be <code>null</code>.
 839   
      *
 840   
      * @return a URL for reading the resource, or <code>null</code> if the
 841   
      *         resource could not be found or the caller doesn't have
 842   
      *         adequate privileges to get the resource.
 843   
      */
 844  7
     public URL getResource(String name) {
 845   
         // we need to search the components of the path to see if
 846   
         // we can find the class we want.
 847  7
         URL url = null;
 848  7
         if (isParentFirst(name)) {
 849  6
             url = (parent == null) ? super.getResource(name)
 850   
                                    : parent.getResource(name);
 851   
         }
 852   
 
 853  7
         if (url != null) {
 854  0
             log("Resource " + name + " loaded from parent loader",
 855   
                 Project.MSG_DEBUG);
 856   
 
 857   
         } else {
 858   
             // try and load from this loader if the parent either didn't find
 859   
             // it or wasn't consulted.
 860  7
             Enumeration e = pathComponents.elements();
 861  7
             while (e.hasMoreElements() && url == null) {
 862  11
                 File pathComponent = (File) e.nextElement();
 863  11
                 url = getResourceURL(pathComponent, name);
 864  11
                 if (url != null) {
 865  7
                     log("Resource " + name
 866   
                         + " loaded from ant loader",
 867   
                         Project.MSG_DEBUG);
 868   
                 }
 869   
             }
 870   
         }
 871   
 
 872  7
         if (url == null && !isParentFirst(name)) {
 873   
             // this loader was first but it didn't find it - try the parent
 874   
 
 875  0
             url = (parent == null) ? super.getResource(name)
 876   
                 : parent.getResource(name);
 877  0
             if (url != null) {
 878  0
                 log("Resource " + name + " loaded from parent loader",
 879   
                     Project.MSG_DEBUG);
 880   
             }
 881   
         }
 882   
 
 883  7
         if (url == null) {
 884  0
             log("Couldn't load Resource " + name, Project.MSG_DEBUG);
 885   
         }
 886   
 
 887  7
         return url;
 888   
     }
 889   
 
 890   
     /**
 891   
      * Returns an enumeration of URLs representing all the resources with the
 892   
      * given name by searching the class loader's classpath.
 893   
      *
 894   
      * @param name The resource name to search for.
 895   
      *             Must not be <code>null</code>.
 896   
      * @return an enumeration of URLs for the resources
 897   
      * @exception IOException if I/O errors occurs (can't happen)
 898   
      */
 899  0
     protected Enumeration findResources(String name) throws IOException {
 900  0
         return new ResourceEnumeration(name);
 901   
     }
 902   
 
 903   
     /**
 904   
      * Returns the URL of a given resource in the given file which may
 905   
      * either be a directory or a zip file.
 906   
      *
 907   
      * @param file The file (directory or jar) in which to search for
 908   
      *             the resource. Must not be <code>null</code>.
 909   
      * @param resourceName The name of the resource for which a stream
 910   
      *                     is required. Must not be <code>null</code>.
 911   
      *
 912   
      * @return a stream to the required resource or <code>null</code> if the
 913   
      *         resource cannot be found in the given file object.
 914   
      */
 915  11
     protected URL getResourceURL(File file, String resourceName) {
 916  11
         try {
 917  11
             if (!file.exists()) {
 918  0
                 return null;
 919   
             }
 920   
 
 921  11
             if (file.isDirectory()) {
 922  11
                 File resource = new File(file, resourceName);
 923   
 
 924  11
                 if (resource.exists()) {
 925  7
                     try {
 926  7
                         return new URL("file:" + resource.toString());
 927   
                     } catch (MalformedURLException ex) {
 928  0
                         return null;
 929   
                     }
 930   
                 }
 931   
             } else {
 932  0
                 ZipFile zipFile = (ZipFile) zipFiles.get(file);
 933  0
                 if (zipFile == null) {
 934  0
                     zipFile = new ZipFile(file);
 935  0
                     zipFiles.put(file, zipFile);
 936   
                 }
 937   
 
 938  0
                 ZipEntry entry = zipFile.getEntry(resourceName);
 939  0
                 if (entry != null) {
 940  0
                     try {
 941  0
                         return new URL("jar:file:" + file.toString()
 942   
                             + "!/" + entry);
 943   
                     } catch (MalformedURLException ex) {
 944  0
                         return null;
 945   
                     }
 946   
                 }
 947   
             }
 948   
         } catch (Exception e) {
 949  0
             e.printStackTrace();
 950   
         }
 951   
 
 952  4
         return null;
 953   
     }
 954   
 
 955   
     /**
 956   
      * Loads a class with this class loader.
 957   
      *
 958   
      * This class attempts to load the class in an order determined by whether
 959   
      * or not the class matches the system/loader package lists, with the
 960   
      * loader package list taking priority. If the classloader is in isolated
 961   
      * mode, failure to load the class in this loader will result in a
 962   
      * ClassNotFoundException.
 963   
      *
 964   
      * @param classname The name of the class to be loaded.
 965   
      *                  Must not be <code>null</code>.
 966   
      * @param resolve <code>true</code> if all classes upon which this class
 967   
      *                depends are to be loaded.
 968   
      *
 969   
      * @return the required Class object
 970   
      *
 971   
      * @exception ClassNotFoundException if the requested class does not exist
 972   
      * on the system classpath (when not in isolated mode) or this loader's
 973   
      * classpath.
 974   
      */
 975  4177
     protected synchronized Class loadClass(String classname, boolean resolve)
 976   
          throws ClassNotFoundException {
 977   
         // 'sync' is needed - otherwise 2 threads can load the same class
 978   
         // twice, resulting in LinkageError: duplicated class definition.
 979   
         // findLoadedClass avoids that, but without sync it won't work.
 980   
 
 981  4177
         Class theClass = findLoadedClass(classname);
 982  4177
         if (theClass != null) {
 983  5
             return theClass;
 984   
         }
 985   
 
 986  4172
         if (isParentFirst(classname)) {
 987  2723
             try {
 988  2723
                 theClass = findBaseClass(classname);
 989  2245
                 log("Class " + classname + " loaded from parent loader " 
 990   
                     + "(parentFirst)", Project.MSG_DEBUG);
 991   
             } catch (ClassNotFoundException cnfe) {
 992  478
                 theClass = findClass(classname);
 993  470
                 log("Class " + classname + " loaded from ant loader " 
 994   
                     + "(parentFirst)", Project.MSG_DEBUG);
 995   
             }
 996   
         } else {
 997  1449
             try {
 998  1449
                 theClass = findClass(classname);
 999  31
                 log("Class " + classname + " loaded from ant loader",
 1000   
                     Project.MSG_DEBUG);
 1001   
             } catch (ClassNotFoundException cnfe) {
 1002  1418
                 if (ignoreBase) {
 1003  0
                     throw cnfe;
 1004   
                 }
 1005  1418
                 theClass = findBaseClass(classname);
 1006  1418
                 log("Class " + classname + " loaded from parent loader",
 1007   
                     Project.MSG_DEBUG);
 1008   
             }
 1009   
         }
 1010   
 
 1011  4164
         if (resolve) {
 1012  0
             resolveClass(theClass);
 1013   
         }
 1014   
 
 1015  4164
         return theClass;
 1016   
     }
 1017   
 
 1018   
     /**
 1019   
      * Converts the class dot notation to a filesystem equivalent for
 1020   
      * searching purposes.
 1021   
      *
 1022   
      * @param classname The class name in dot format (eg java.lang.Integer).
 1023   
      *                  Must not be <code>null</code>.
 1024   
      *
 1025   
      * @return the classname in filesystem format (eg java/lang/Integer.class)
 1026   
      */
 1027  1938
     private String getClassFilename(String classname) {
 1028  1938
         return classname.replace('.', '/') + ".class";
 1029   
     }
 1030   
 
 1031   
     /**
 1032   
      * Define a class given its bytes
 1033   
      *
 1034   
      * @param container the container from which the class data has been read
 1035   
      *                  may be a directory or a jar/zip file.
 1036   
      *
 1037   
      * @param classData the bytecode data for the class
 1038   
      * @param classname the name of the class
 1039   
      *
 1040   
      * @return the Class instance created from the given data
 1041   
      *
 1042   
      * @throws IOException if the class data cannot be read.
 1043   
      */
 1044  0
     protected Class defineClassFromData(File container, byte[] classData,
 1045   
                                         String classname) throws IOException {
 1046   
         // Simply put:
 1047   
         // defineClass(classname, classData, 0, classData.length,
 1048   
         //             Project.class.getProtectionDomain());
 1049   
         // Made more elaborate to be 1.1-safe.
 1050  0
         if (defineClassProtectionDomain != null) {
 1051  0
             try {
 1052  0
                 Object domain
 1053   
                     = getProtectionDomain.invoke(Project.class, new Object[0]);
 1054  0
                 Object[] args
 1055   
                     = new Object[] {classname, classData, new Integer(0),
 1056   
                                     new Integer(classData.length), domain};
 1057  0
                 return (Class) defineClassProtectionDomain.invoke(this, args);
 1058   
             } catch (InvocationTargetException ite) {
 1059  0
                 Throwable t = ite.getTargetException();
 1060  0
                 if (t instanceof ClassFormatError) {
 1061  0
                     throw (ClassFormatError) t;
 1062  0
                 } else if (t instanceof NoClassDefFoundError) {
 1063  0
                     throw (NoClassDefFoundError) t;
 1064  0
                 } else if (t instanceof SecurityException) {
 1065  0
                     throw (SecurityException) t;
 1066   
                 } else {
 1067  0
                     throw new IOException(t.toString());
 1068   
                 }
 1069   
             } catch (Exception e) {
 1070  0
                 throw new IOException(e.toString());
 1071   
             }
 1072   
         } else {
 1073  0
             return defineClass(classname, classData, 0, classData.length);
 1074   
         }
 1075   
     }
 1076   
     
 1077   
     /**
 1078   
      * Reads a class definition from a stream.
 1079   
      *
 1080   
      * @param stream The stream from which the class is to be read.
 1081   
      *               Must not be <code>null</code>.
 1082   
      * @param classname The name of the class in the stream.
 1083   
      *                  Must not be <code>null</code>.
 1084   
      * @param container the file or directory containing the class.
 1085   
      *
 1086   
      * @return the Class object read from the stream.
 1087   
      *
 1088   
      * @exception IOException if there is a problem reading the class from the
 1089   
      * stream.
 1090   
      * @exception SecurityException if there is a security problem while
 1091   
      * reading the class from the stream.
 1092   
      */
 1093  508
     private Class getClassFromStream(InputStream stream, String classname,
 1094   
                                        File container)
 1095   
                 throws IOException, SecurityException {
 1096  508
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 1097  508
         int bytesRead = -1;
 1098  508
         byte[] buffer = new byte[BUFFER_SIZE];
 1099   
 
 1100  ?
         while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) {
 1101  516
             baos.write(buffer, 0, bytesRead);
 1102   
         }
 1103   
 
 1104  508
         byte[] classData = baos.toByteArray();
 1105  508
         return defineClassFromData(container, classData, classname);
 1106   
     }
 1107   
 
 1108   
     /**
 1109   
      * Searches for and load a class on the classpath of this class loader.
 1110   
      *
 1111   
      * @param name The name of the class to be loaded. Must not be
 1112   
      *             <code>null</code>.
 1113   
      *
 1114   
      * @return the required Class object
 1115   
      *
 1116   
      * @exception ClassNotFoundException if the requested class does not exist
 1117   
      *                                   on this loader's classpath.
 1118   
      */
 1119  1938
     public Class findClass(String name) throws ClassNotFoundException {
 1120  1938
         log("Finding class " + name, Project.MSG_DEBUG);
 1121   
 
 1122  1938
         return findClassInComponents(name);
 1123   
     }
 1124   
 
 1125   
     /** 
 1126   
      * Indicate if the given file is in this loader's path
 1127   
      *
 1128   
      * @param component the file which is to be checked
 1129   
      *
 1130   
      * @return true if the file is in the class path
 1131   
      */
 1132  118
     protected boolean isInPath(File component) {
 1133  1106
         for (Enumeration e = pathComponents.elements(); e.hasMoreElements();) {
 1134  1106
             File pathComponent = (File) e.nextElement();
 1135  1106
             if (pathComponent.equals(component)) {
 1136  118
                 return true;
 1137   
             }
 1138   
         }
 1139  0
         return false;
 1140   
     }
 1141   
     
 1142   
 
 1143   
     /**
 1144   
      * Finds a class on the given classpath.
 1145   
      *
 1146   
      * @param name The name of the class to be loaded. Must not be
 1147   
      *             <code>null</code>.
 1148   
      *
 1149   
      * @return the required Class object
 1150   
      *
 1151   
      * @exception ClassNotFoundException if the requested class does not exist
 1152   
      * on this loader's classpath.
 1153   
      */
 1154  1938
     private Class findClassInComponents(String name)
 1155   
          throws ClassNotFoundException {
 1156   
         // we need to search the components of the path to see if
 1157   
         // we can find the class we want.
 1158  1938
         InputStream stream = null;
 1159  1938
         String classFilename = getClassFilename(name);
 1160  1938
         try {
 1161  1938
             Enumeration e = pathComponents.elements();
 1162  1938
             while (e.hasMoreElements()) {
 1163  11011
                 File pathComponent = (File) e.nextElement();
 1164  11011
                 try {
 1165  11011
                     stream = getResourceStream(pathComponent, classFilename);
 1166  11011
                     if (stream != null) {
 1167  508
                         log("Loaded from " + pathComponent + " " 
 1168   
                             + classFilename, Project.MSG_DEBUG);
 1169  508
                         return getClassFromStream(stream, name, pathComponent);
 1170   
                     }
 1171   
                 } catch (SecurityException se) {
 1172  1
                     throw se;
 1173   
                 } catch (IOException ioe) {
 1174   
                     // ioe.printStackTrace();
 1175  0
                     log("Exception reading component " + pathComponent
 1176   
                         + " (reason: " + ioe.getMessage() + ")",
 1177   
                         Project.MSG_VERBOSE);
 1178   
                 }
 1179   
             }
 1180   
 
 1181  1430
             throw new ClassNotFoundException(name);
 1182   
         } finally {
 1183  1938
             try {
 1184  1938
                 if (stream != null) {
 1185  508
                     stream.close();
 1186   
                 }
 1187   
             } catch (IOException e) {}
 1188   
         }
 1189   
     }
 1190   
 
 1191   
     /**
 1192   
      * Finds a system class (which should be loaded from the same classloader
 1193   
      * as the Ant core).
 1194   
      *
 1195   
      * For JDK 1.1 compatability, this uses the findSystemClass method if
 1196   
      * no parent classloader has been specified.
 1197   
      *
 1198   
      * @param name The name of the class to be loaded.
 1199   
      *             Must not be <code>null</code>.
 1200   
      *
 1201   
      * @return the required Class object
 1202   
      *
 1203   
      * @exception ClassNotFoundException if the requested class does not exist
 1204   
      * on this loader's classpath.
 1205   
      */
 1206  4163
     private Class findBaseClass(String name) throws ClassNotFoundException {
 1207  4163
         if (parent == null) {
 1208  0
             return findSystemClass(name);
 1209   
         } else {
 1210  4163
             return parent.loadClass(name);
 1211   
         }
 1212   
     }
 1213   
 
 1214   
     /**
 1215   
      * Cleans up any resources held by this classloader. Any open archive
 1216   
      * files are closed.
 1217   
      */
 1218  210
     public synchronized void cleanup() {
 1219  210
         for (Enumeration e = zipFiles.elements(); e.hasMoreElements();) {
 1220  278
             ZipFile zipFile = (ZipFile) e.nextElement();
 1221  278
             try {
 1222  278
                 zipFile.close();
 1223   
             } catch (IOException ioe) {
 1224   
                 // ignore
 1225   
             }
 1226   
         }
 1227  210
         zipFiles = new Hashtable();
 1228   
     }
 1229   
 
 1230   
     /**
 1231   
      * Empty implementation to satisfy the BuildListener interface.
 1232   
      *
 1233   
      * @param event the buildStarted event
 1234   
      */
 1235  0
     public void buildStarted(BuildEvent event) {
 1236   
     }
 1237   
 
 1238   
     /**
 1239   
      * Cleans up any resources held by this classloader at the end
 1240   
      * of a build.
 1241   
      *
 1242   
      * @param event the buildFinished event
 1243   
      */
 1244  172
     public void buildFinished(BuildEvent event) {
 1245  172
         project.removeBuildListener(this);
 1246  172
         project = null;
 1247  172
         cleanup();
 1248   
     }
 1249   
 
 1250   
     /**
 1251   
      * Empty implementation to satisfy the BuildListener interface.
 1252   
      *
 1253   
      * @param event the targetStarted event
 1254   
      */
 1255  350
     public void targetStarted(BuildEvent event) {
 1256   
     }
 1257   
 
 1258   
     /**
 1259   
      * Empty implementation to satisfy the BuildListener interface.
 1260   
      *
 1261   
      * @param event the targetFinished event
 1262   
      */
 1263  570
     public void targetFinished(BuildEvent event) {
 1264   
     }
 1265   
 
 1266   
     /**
 1267   
      * Empty implementation to satisfy the BuildListener interface.
 1268   
      *
 1269   
      * @param event the taskStarted event
 1270   
      */
 1271  1818
     public void taskStarted(BuildEvent event) {
 1272   
     }
 1273   
 
 1274   
     /**
 1275   
      * Empty implementation to satisfy the BuildListener interface.
 1276   
      *
 1277   
      * @param event the taskFinished event
 1278   
      */
 1279  2060
     public void taskFinished(BuildEvent event) {
 1280   
     }
 1281   
 
 1282   
     /**
 1283   
      * Empty implementation to satisfy the BuildListener interface.
 1284   
      *
 1285   
      * @param event the messageLogged event
 1286   
      */
 1287  881632
     public void messageLogged(BuildEvent event) {
 1288   
     }
 1289   
 
 1290   
     /**
 1291   
      * add any libraries that come with different java versions
 1292   
      * here
 1293   
      */
 1294  144
     public void addJavaLibraries() {
 1295  144
         Vector packages = JavaEnvUtils.getJrePackages();
 1296  144
         Enumeration e = packages.elements();
 1297  144
         while (e.hasMoreElements()) {
 1298  3024
             String packageName = (String) e.nextElement();
 1299  3024
             addSystemPackageRoot(packageName);
 1300   
         }
 1301   
     }
 1302   
 
 1303   
 }
 1304