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 */ TestCaseClassLoader()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 */ TestCaseClassLoader(String classPath)50 public TestCaseClassLoader(String classPath) { 51 scanPath(classPath); 52 readExcludedPackages(); 53 } 54 scanPath(String classPath)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 getResource(String name)64 public URL getResource(String name) { 65 return ClassLoader.getSystemResource(name); 66 } 67 getResourceAsStream(String name)68 public InputStream getResourceAsStream(String name) { 69 return ClassLoader.getSystemResourceAsStream(name); 70 } 71 isExcluded(String name)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 loadClass(String name, boolean resolve)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 lookupClassData(String className)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 isJar(String pathEntry)126 boolean isJar(String pathEntry) { 127 return pathEntry.endsWith(".jar") || 128 pathEntry.endsWith(".apk") || 129 pathEntry.endsWith(".zip"); 130 } 131 loadFileData(String path, String fileName)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 getClassData(File f)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 loadJarData(String path, String fileName)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 readExcludedPackages()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