• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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