blob: 09eec7f2e90383b44033e0df29acccbd07e92fdf [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001package junit.runner;
2
3import java.util.*;
4import java.io.*;
5import java.net.URL;
6import 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
Brett Chabotf1253cd2012-01-30 11:29:54 -080017 * a properties file "excluded.properties" that is located in
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018 * 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 */
24public class TestCaseClassLoader extends ClassLoader {
Brett Chabotf1253cd2012-01-30 11:29:54 -080025 /** 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
Brett Chabotf1253cd2012-01-30 11:29:54 -080038 /**
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045
Brett Chabotf1253cd2012-01-30 11:29:54 -080046 /**
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
Brett Chabotf1253cd2012-01-30 11:29:54 -080055 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
Brett Chabotf1253cd2012-01-30 11:29:54 -080064 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225}