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