You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ClassPoolTail.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist;
  16. import java.io.*;
  17. import java.util.jar.*;
  18. import java.net.MalformedURLException;
  19. import java.net.URL;
  20. import java.util.Hashtable;
  21. final class ClassPathList {
  22. ClassPathList next;
  23. ClassPath path;
  24. ClassPathList(ClassPath p, ClassPathList n) {
  25. next = n;
  26. path = p;
  27. }
  28. }
  29. final class DirClassPath implements ClassPath {
  30. String directory;
  31. DirClassPath(String dirName) {
  32. directory = dirName;
  33. }
  34. public InputStream openClassfile(String classname) {
  35. try {
  36. char sep = File.separatorChar;
  37. String filename = directory + sep
  38. + classname.replace('.', sep) + ".class";
  39. return new FileInputStream(filename.toString());
  40. }
  41. catch (FileNotFoundException e) {}
  42. catch (SecurityException e) {}
  43. return null;
  44. }
  45. public URL find(String classname) {
  46. char sep = File.separatorChar;
  47. String filename = directory + sep
  48. + classname.replace('.', sep) + ".class";
  49. File f = new File(filename);
  50. if (f.exists())
  51. try {
  52. return f.getCanonicalFile().toURL();
  53. }
  54. catch (MalformedURLException e) {}
  55. catch (IOException e) {}
  56. return null;
  57. }
  58. public void close() {}
  59. public String toString() {
  60. return directory;
  61. }
  62. }
  63. final class JarClassPath implements ClassPath {
  64. JarFile jarfile;
  65. String jarfileURL;
  66. JarClassPath(String pathname) throws NotFoundException {
  67. try {
  68. jarfile = new JarFile(pathname);
  69. jarfileURL = new File(pathname).getCanonicalFile()
  70. .toURL().toString();
  71. return;
  72. }
  73. catch (IOException e) {}
  74. throw new NotFoundException(pathname);
  75. }
  76. public InputStream openClassfile(String classname)
  77. throws NotFoundException
  78. {
  79. try {
  80. String jarname = classname.replace('.', '/') + ".class";
  81. JarEntry je = jarfile.getJarEntry(jarname);
  82. if (je != null)
  83. return jarfile.getInputStream(je);
  84. else
  85. return null; // not found
  86. }
  87. catch (IOException e) {}
  88. throw new NotFoundException("broken jar file?: "
  89. + jarfile.getName());
  90. }
  91. public URL find(String classname) {
  92. String jarname = classname.replace('.', '/') + ".class";
  93. JarEntry je = jarfile.getJarEntry(jarname);
  94. if (je != null)
  95. try {
  96. return new URL("jar:" + jarfileURL + "!/" + jarname);
  97. }
  98. catch (MalformedURLException e) {}
  99. return null; // not found
  100. }
  101. public void close() {
  102. try {
  103. jarfile.close();
  104. jarfile = null;
  105. }
  106. catch (IOException e) {}
  107. }
  108. public String toString() {
  109. return jarfile == null ? "<null>" : jarfile.toString();
  110. }
  111. }
  112. final class ClassPoolTail {
  113. protected ClassPathList pathList;
  114. private Hashtable packages; // should be synchronized.
  115. public ClassPoolTail() {
  116. pathList = null;
  117. packages = new Hashtable();
  118. }
  119. public String toString() {
  120. StringBuffer buf = new StringBuffer();
  121. buf.append("[class path: ");
  122. ClassPathList list = pathList;
  123. while (list != null) {
  124. buf.append(list.path.toString());
  125. buf.append(File.pathSeparatorChar);
  126. list = list.next;
  127. }
  128. buf.append(']');
  129. return buf.toString();
  130. }
  131. public synchronized ClassPath insertClassPath(ClassPath cp) {
  132. pathList = new ClassPathList(cp, pathList);
  133. return cp;
  134. }
  135. public synchronized ClassPath appendClassPath(ClassPath cp) {
  136. ClassPathList tail = new ClassPathList(cp, null);
  137. ClassPathList list = pathList;
  138. if (list == null)
  139. pathList = tail;
  140. else {
  141. while (list.next != null)
  142. list = list.next;
  143. list.next = tail;
  144. }
  145. return cp;
  146. }
  147. public synchronized void removeClassPath(ClassPath cp) {
  148. ClassPathList list = pathList;
  149. if (list != null)
  150. if (list.path == cp)
  151. pathList = list.next;
  152. else {
  153. while (list.next != null)
  154. if (list.next.path == cp)
  155. list.next = list.next.next;
  156. else
  157. list = list.next;
  158. }
  159. cp.close();
  160. }
  161. public ClassPath appendSystemPath() {
  162. return appendClassPath(new ClassClassPath());
  163. }
  164. public ClassPath insertClassPath(String pathname)
  165. throws NotFoundException
  166. {
  167. return insertClassPath(makePathObject(pathname));
  168. }
  169. public ClassPath appendClassPath(String pathname)
  170. throws NotFoundException
  171. {
  172. return appendClassPath(makePathObject(pathname));
  173. }
  174. private static ClassPath makePathObject(String pathname)
  175. throws NotFoundException
  176. {
  177. int i = pathname.lastIndexOf('.');
  178. if (i >= 0) {
  179. String ext = pathname.substring(i).toLowerCase();
  180. if (ext.equals(".jar") || ext.equals(".zip"))
  181. return new JarClassPath(pathname);
  182. }
  183. return new DirClassPath(pathname);
  184. }
  185. /**
  186. * You can record "System" so that java.lang.System can be quickly
  187. * found although "System" is not a package name.
  188. */
  189. public void recordInvalidClassName(String name) {
  190. packages.put(name, name);
  191. }
  192. /**
  193. * This method does not close the output stream.
  194. */
  195. void writeClassfile(String classname, OutputStream out)
  196. throws NotFoundException, IOException, CannotCompileException
  197. {
  198. InputStream fin = openClassfile(classname);
  199. if (fin == null)
  200. throw new NotFoundException(classname);
  201. try {
  202. copyStream(fin, out);
  203. }
  204. finally {
  205. fin.close();
  206. }
  207. }
  208. /*
  209. -- faster version --
  210. void checkClassName(String classname) throws NotFoundException {
  211. if (find(classname) == null)
  212. throw new NotFoundException(classname);
  213. }
  214. -- slower version --
  215. void checkClassName(String classname) throws NotFoundException {
  216. InputStream fin = openClassfile(classname);
  217. try {
  218. fin.close();
  219. }
  220. catch (IOException e) {}
  221. }
  222. */
  223. /**
  224. * Opens the class file for the class specified by
  225. * <code>classname</code>.
  226. *
  227. * @param classname a fully-qualified class name
  228. * @return null if the file has not been found.
  229. * @throws NotFoundException if any error is reported by ClassPath.
  230. */
  231. InputStream openClassfile(String classname)
  232. throws NotFoundException
  233. {
  234. if (packages.get(classname) != null)
  235. return null; // not found
  236. ClassPathList list = pathList;
  237. InputStream ins = null;
  238. NotFoundException error = null;
  239. while (list != null) {
  240. try {
  241. ins = list.path.openClassfile(classname);
  242. }
  243. catch (NotFoundException e) {
  244. if (error == null)
  245. error = e;
  246. }
  247. if (ins == null)
  248. list = list.next;
  249. else
  250. return ins;
  251. }
  252. if (error != null)
  253. throw error;
  254. else
  255. return null; // not found
  256. }
  257. /**
  258. * Searches the class path to obtain the URL of the class file
  259. * specified by classname. It is also used to determine whether
  260. * the class file exists.
  261. *
  262. * @param classname a fully-qualified class name.
  263. * @return null if the class file could not be found.
  264. */
  265. public URL find(String classname) {
  266. if (packages.get(classname) != null)
  267. return null;
  268. ClassPathList list = pathList;
  269. URL url = null;
  270. while (list != null) {
  271. url = list.path.find(classname);
  272. if (url == null)
  273. list = list.next;
  274. else
  275. return url;
  276. }
  277. return null;
  278. }
  279. /**
  280. * Reads from an input stream until it reaches the end.
  281. *
  282. * @return the contents of that input stream
  283. */
  284. public static byte[] readStream(InputStream fin) throws IOException {
  285. byte[][] bufs = new byte[8][];
  286. int bufsize = 4096;
  287. for (int i = 0; i < 8; ++i) {
  288. bufs[i] = new byte[bufsize];
  289. int size = 0;
  290. int len = 0;
  291. do {
  292. len = fin.read(bufs[i], size, bufsize - size);
  293. if (len >= 0)
  294. size += len;
  295. else {
  296. byte[] result = new byte[bufsize - 4096 + size];
  297. int s = 0;
  298. for (int j = 0; j < i; ++j) {
  299. System.arraycopy(bufs[j], 0, result, s, s + 4096);
  300. s = s + s + 4096;
  301. }
  302. System.arraycopy(bufs[i], 0, result, s, size);
  303. return result;
  304. }
  305. } while (size < bufsize);
  306. bufsize *= 2;
  307. }
  308. throw new IOException("too much data");
  309. }
  310. /**
  311. * Reads from an input stream and write to an output stream
  312. * until it reaches the end. This method does not close the
  313. * streams.
  314. */
  315. public static void copyStream(InputStream fin, OutputStream fout)
  316. throws IOException
  317. {
  318. int bufsize = 4096;
  319. for (int i = 0; i < 8; ++i) {
  320. byte[] buf = new byte[bufsize];
  321. int size = 0;
  322. int len = 0;
  323. do {
  324. len = fin.read(buf, size, bufsize - size);
  325. if (len >= 0)
  326. size += len;
  327. else {
  328. fout.write(buf, 0, size);
  329. return;
  330. }
  331. } while (size < bufsize);
  332. fout.write(buf);
  333. bufsize *= 2;
  334. }
  335. throw new IOException("too much data");
  336. }
  337. }