Home | History | Annotate | Download | only in runner
      1 package junit.runner;
      2 
      3 import java.util.*;
      4 import java.io.*;
      5 import java.net.URL;
      6 import java.util.zip.*;
      7 
      8 /**
      9  * A custom class loader which enables the reloading
     10  * of classes for each test run. The class loader
     11  * can be configured with a list of package paths that
     12  * should be excluded from loading. The loading
     13  * of these packages is delegated to the system class
     14  * loader. They will be shared across test runs.
     15  * <p>
     16  * The list of excluded package paths is specified in
     17  * a properties file "excluded.properties" that is located in
     18  * the same place as the TestCaseClassLoader class.
     19  * <p>
     20  * <b>Known limitation:</b> the TestCaseClassLoader cannot load classes
     21  * from jar files.
     22  * {@hide} - Not needed for 1.0 SDK
     23  */
     24 public class TestCaseClassLoader extends ClassLoader {
     25     /** scanned class path */
     26     private Vector fPathItems;
     27     /** default excluded paths */
     28     private String[] defaultExclusions= {
     29             "junit.framework.",
     30             "junit.extensions.",
     31             "junit.runner."
     32     };
     33     /** name of excluded properties file */
     34     static final String EXCLUDED_FILE= "excluded.properties";
     35     /** excluded paths */
     36     private Vector fExcluded;
     37 
     38     /**
     39      * Constructs a TestCaseLoader. It scans the class path
     40      * and the excluded package paths
     41      */
     42     public TestCaseClassLoader() {
     43         this(System.getProperty("java.class.path"));
     44     }
     45 
     46     /**
     47      * Constructs a TestCaseLoader. It scans the class path
     48      * and the excluded package paths
     49      */
     50     public TestCaseClassLoader(String classPath) {
     51         scanPath(classPath);
     52         readExcludedPackages();
     53     }
     54 
     55     private void scanPath(String classPath) {
     56         String separator= System.getProperty("path.separator");
     57         fPathItems= new Vector(10);
     58         StringTokenizer st= new StringTokenizer(classPath, separator);
     59         while (st.hasMoreTokens()) {
     60             fPathItems.addElement(st.nextToken());
     61         }
     62     }
     63 
     64     public URL getResource(String name) {
     65         return ClassLoader.getSystemResource(name);
     66     }
     67 
     68     public InputStream getResourceAsStream(String name) {
     69         return ClassLoader.getSystemResourceAsStream(name);
     70     }
     71 
     72     public boolean isExcluded(String name) {
     73         for (int i= 0; i < fExcluded.size(); i++) {
     74             if (name.startsWith((String) fExcluded.elementAt(i))) {
     75                 return true;
     76             }
     77         }
     78         return false;
     79     }
     80 
     81     public synchronized Class loadClass(String name, boolean resolve)
     82             throws ClassNotFoundException {
     83 
     84         Class c= findLoadedClass(name);
     85         if (c != null)
     86             return c;
     87         //
     88         // Delegate the loading of excluded classes to the
     89         // standard class loader.
     90         //
     91         if (isExcluded(name)) {
     92             try {
     93                 c= findSystemClass(name);
     94                 return c;
     95             } catch (ClassNotFoundException e) {
     96                 // keep searching
     97             }
     98         }
     99         if (c == null) {
    100             byte[] data= lookupClassData(name);
    101             if (data == null)
    102                 throw new ClassNotFoundException();
    103             c= defineClass(name, data, 0, data.length);
    104         }
    105         if (resolve)
    106             resolveClass(c);
    107         return c;
    108     }
    109 
    110     private byte[] lookupClassData(String className) throws ClassNotFoundException {
    111         byte[] data= null;
    112         for (int i= 0; i < fPathItems.size(); i++) {
    113             String path= (String) fPathItems.elementAt(i);
    114             String fileName= className.replace('.', '/')+".class";
    115             if (isJar(path)) {
    116                 data= loadJarData(path, fileName);
    117             } else {
    118                 data= loadFileData(path, fileName);
    119             }
    120             if (data != null)
    121                 return data;
    122         }
    123         throw new ClassNotFoundException(className);
    124     }
    125 
    126     boolean isJar(String pathEntry) {
    127         return pathEntry.endsWith(".jar") ||
    128                 pathEntry.endsWith(".apk") ||
    129                 pathEntry.endsWith(".zip");
    130     }
    131 
    132     private byte[] loadFileData(String path, String fileName) {
    133         File file= new File(path, fileName);
    134         if (file.exists()) {
    135             return getClassData(file);
    136         }
    137         return null;
    138     }
    139 
    140     private byte[] getClassData(File f) {
    141         try {
    142             FileInputStream stream= new FileInputStream(f);
    143             ByteArrayOutputStream out= new ByteArrayOutputStream(1000);
    144             byte[] b= new byte[1000];
    145             int n;
    146             while ((n= stream.read(b)) != -1)
    147                 out.write(b, 0, n);
    148             stream.close();
    149             out.close();
    150             return out.toByteArray();
    151 
    152         } catch (IOException e) {
    153         }
    154         return null;
    155     }
    156 
    157     private byte[] loadJarData(String path, String fileName) {
    158         ZipFile zipFile= null;
    159         InputStream stream= null;
    160         File archive= new File(path);
    161         if (!archive.exists())
    162             return null;
    163         try {
    164             zipFile= new ZipFile(archive);
    165         } catch(IOException io) {
    166             return null;
    167         }
    168         ZipEntry entry= zipFile.getEntry(fileName);
    169         if (entry == null)
    170             return null;
    171         int size= (int) entry.getSize();
    172         try {
    173             stream= zipFile.getInputStream(entry);
    174             byte[] data= new byte[size];
    175             int pos= 0;
    176             while (pos < size) {
    177                 int n= stream.read(data, pos, data.length - pos);
    178                 pos += n;
    179             }
    180             zipFile.close();
    181             return data;
    182         } catch (IOException e) {
    183         } finally {
    184             try {
    185                 if (stream != null)
    186                     stream.close();
    187             } catch (IOException e) {
    188             }
    189         }
    190         return null;
    191     }
    192 
    193     private void readExcludedPackages() {
    194         fExcluded= new Vector(10);
    195         for (int i= 0; i < defaultExclusions.length; i++)
    196             fExcluded.addElement(defaultExclusions[i]);
    197 
    198         InputStream is= getClass().getResourceAsStream(EXCLUDED_FILE);
    199         if (is == null)
    200             return;
    201         Properties p= new Properties();
    202         try {
    203             p.load(is);
    204         }
    205         catch (IOException e) {
    206             return;
    207         } finally {
    208             try {
    209                 is.close();
    210             } catch (IOException e) {
    211             }
    212         }
    213         for (Enumeration e= p.propertyNames(); e.hasMoreElements(); ) {
    214             String key= (String)e.nextElement();
    215             if (key.startsWith("excluded.")) {
    216                 String path= p.getProperty(key);
    217                 path= path.trim();
    218                 if (path.endsWith("*"))
    219                     path= path.substring(0, path.length()-1);
    220                 if (path.length() > 0)
    221                     fExcluded.addElement(path);
    222             }
    223         }
    224     }
    225 }
    226