001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist;
017:
018: import java.io.*;
019: import java.util.jar.*;
020: import java.net.MalformedURLException;
021: import java.net.URL;
022: import java.util.Hashtable;
023:
024: final class ClassPathList {
025: ClassPathList next;
026: ClassPath path;
027:
028: ClassPathList(ClassPath p, ClassPathList n) {
029: next = n;
030: path = p;
031: }
032: }
033:
034: final class DirClassPath implements ClassPath {
035: String directory;
036:
037: DirClassPath(String dirName) {
038: directory = dirName;
039: }
040:
041: public InputStream openClassfile(String classname) {
042: try {
043: char sep = File.separatorChar;
044: String filename = directory + sep
045: + classname.replace('.', sep) + ".class";
046: return new FileInputStream(filename.toString());
047: } catch (FileNotFoundException e) {
048: } catch (SecurityException e) {
049: }
050: return null;
051: }
052:
053: public URL find(String classname) {
054: char sep = File.separatorChar;
055: String filename = directory + sep + classname.replace('.', sep)
056: + ".class";
057: File f = new File(filename);
058: if (f.exists())
059: try {
060: return f.getCanonicalFile().toURL();
061: } catch (MalformedURLException e) {
062: } catch (IOException e) {
063: }
064:
065: return null;
066: }
067:
068: public void close() {
069: }
070:
071: public String toString() {
072: return directory;
073: }
074: }
075:
076: final class JarClassPath implements ClassPath {
077: JarFile jarfile;
078: String jarfileURL;
079:
080: JarClassPath(String pathname) throws NotFoundException {
081: try {
082: jarfile = new JarFile(pathname);
083: jarfileURL = new File(pathname).getCanonicalFile().toURL()
084: .toString();
085: return;
086: } catch (IOException e) {
087: }
088: throw new NotFoundException(pathname);
089: }
090:
091: public InputStream openClassfile(String classname)
092: throws NotFoundException {
093: try {
094: String jarname = classname.replace('.', '/') + ".class";
095: JarEntry je = jarfile.getJarEntry(jarname);
096: if (je != null)
097: return jarfile.getInputStream(je);
098: else
099: return null; // not found
100: } catch (IOException e) {
101: }
102: throw new NotFoundException("broken jar file?: "
103: + jarfile.getName());
104: }
105:
106: public URL find(String classname) {
107: String jarname = classname.replace('.', '/') + ".class";
108: JarEntry je = jarfile.getJarEntry(jarname);
109: if (je != null)
110: try {
111: return new URL("jar:" + jarfileURL + "!/" + jarname);
112: } catch (MalformedURLException e) {
113: }
114:
115: return null; // not found
116: }
117:
118: public void close() {
119: try {
120: jarfile.close();
121: jarfile = null;
122: } catch (IOException e) {
123: }
124: }
125:
126: public String toString() {
127: return jarfile == null ? "<null>" : jarfile.toString();
128: }
129: }
130:
131: final class ClassPoolTail {
132: protected ClassPathList pathList;
133: private Hashtable packages; // should be synchronized.
134:
135: public ClassPoolTail() {
136: pathList = null;
137: packages = new Hashtable();
138: }
139:
140: public String toString() {
141: StringBuffer buf = new StringBuffer();
142: buf.append("[class path: ");
143: ClassPathList list = pathList;
144: while (list != null) {
145: buf.append(list.path.toString());
146: buf.append(File.pathSeparatorChar);
147: list = list.next;
148: }
149:
150: buf.append(']');
151: return buf.toString();
152: }
153:
154: public synchronized ClassPath insertClassPath(ClassPath cp) {
155: pathList = new ClassPathList(cp, pathList);
156: return cp;
157: }
158:
159: public synchronized ClassPath appendClassPath(ClassPath cp) {
160: ClassPathList tail = new ClassPathList(cp, null);
161: ClassPathList list = pathList;
162: if (list == null)
163: pathList = tail;
164: else {
165: while (list.next != null)
166: list = list.next;
167:
168: list.next = tail;
169: }
170:
171: return cp;
172: }
173:
174: public synchronized void removeClassPath(ClassPath cp) {
175: ClassPathList list = pathList;
176: if (list != null)
177: if (list.path == cp)
178: pathList = list.next;
179: else {
180: while (list.next != null)
181: if (list.next.path == cp)
182: list.next = list.next.next;
183: else
184: list = list.next;
185: }
186:
187: cp.close();
188: }
189:
190: public ClassPath appendSystemPath() {
191: return appendClassPath(new ClassClassPath());
192: }
193:
194: public ClassPath insertClassPath(String pathname)
195: throws NotFoundException {
196: return insertClassPath(makePathObject(pathname));
197: }
198:
199: public ClassPath appendClassPath(String pathname)
200: throws NotFoundException {
201: return appendClassPath(makePathObject(pathname));
202: }
203:
204: private static ClassPath makePathObject(String pathname)
205: throws NotFoundException {
206: int i = pathname.lastIndexOf('.');
207: if (i >= 0) {
208: String ext = pathname.substring(i).toLowerCase();
209: if (ext.equals(".jar") || ext.equals(".zip"))
210: return new JarClassPath(pathname);
211: }
212:
213: return new DirClassPath(pathname);
214: }
215:
216: /**
217: * You can record "System" so that java.lang.System can be quickly
218: * found although "System" is not a package name.
219: */
220: public void recordInvalidClassName(String name) {
221: packages.put(name, name);
222: }
223:
224: /**
225: * This method does not close the output stream.
226: */
227: void writeClassfile(String classname, OutputStream out)
228: throws NotFoundException, IOException,
229: CannotCompileException {
230: InputStream fin = openClassfile(classname);
231: if (fin == null)
232: throw new NotFoundException(classname);
233:
234: try {
235: copyStream(fin, out);
236: } finally {
237: fin.close();
238: }
239: }
240:
241: /*
242: -- faster version --
243: void checkClassName(String classname) throws NotFoundException {
244: if (find(classname) == null)
245: throw new NotFoundException(classname);
246: }
247:
248: -- slower version --
249:
250: void checkClassName(String classname) throws NotFoundException {
251: InputStream fin = openClassfile(classname);
252: try {
253: fin.close();
254: }
255: catch (IOException e) {}
256: }
257: */
258:
259: /**
260: * Opens the class file for the class specified by
261: * <code>classname</code>.
262: *
263: * @param classname a fully-qualified class name
264: * @return null if the file has not been found.
265: * @throws NotFoundException if any error is reported by ClassPath.
266: */
267: InputStream openClassfile(String classname)
268: throws NotFoundException {
269: if (packages.get(classname) != null)
270: return null; // not found
271:
272: ClassPathList list = pathList;
273: InputStream ins = null;
274: NotFoundException error = null;
275: while (list != null) {
276: try {
277: ins = list.path.openClassfile(classname);
278: } catch (NotFoundException e) {
279: if (error == null)
280: error = e;
281: }
282:
283: if (ins == null)
284: list = list.next;
285: else
286: return ins;
287: }
288:
289: if (error != null)
290: throw error;
291: else
292: return null; // not found
293: }
294:
295: /**
296: * Searches the class path to obtain the URL of the class file
297: * specified by classname. It is also used to determine whether
298: * the class file exists.
299: *
300: * @param classname a fully-qualified class name.
301: * @return null if the class file could not be found.
302: */
303: public URL find(String classname) {
304: if (packages.get(classname) != null)
305: return null;
306:
307: ClassPathList list = pathList;
308: URL url = null;
309: while (list != null) {
310: url = list.path.find(classname);
311: if (url == null)
312: list = list.next;
313: else
314: return url;
315: }
316:
317: return null;
318: }
319:
320: /**
321: * Reads from an input stream until it reaches the end.
322: *
323: * @return the contents of that input stream
324: */
325: public static byte[] readStream(InputStream fin) throws IOException {
326: byte[][] bufs = new byte[8][];
327: int bufsize = 4096;
328:
329: for (int i = 0; i < 8; ++i) {
330: bufs[i] = new byte[bufsize];
331: int size = 0;
332: int len = 0;
333: do {
334: len = fin.read(bufs[i], size, bufsize - size);
335: if (len >= 0)
336: size += len;
337: else {
338: byte[] result = new byte[bufsize - 4096 + size];
339: int s = 0;
340: for (int j = 0; j < i; ++j) {
341: System.arraycopy(bufs[j], 0, result, s,
342: s + 4096);
343: s = s + s + 4096;
344: }
345:
346: System.arraycopy(bufs[i], 0, result, s, size);
347: return result;
348: }
349: } while (size < bufsize);
350: bufsize *= 2;
351: }
352:
353: throw new IOException("too much data");
354: }
355:
356: /**
357: * Reads from an input stream and write to an output stream
358: * until it reaches the end. This method does not close the
359: * streams.
360: */
361: public static void copyStream(InputStream fin, OutputStream fout)
362: throws IOException {
363: int bufsize = 4096;
364: for (int i = 0; i < 8; ++i) {
365: byte[] buf = new byte[bufsize];
366: int size = 0;
367: int len = 0;
368: do {
369: len = fin.read(buf, size, bufsize - size);
370: if (len >= 0)
371: size += len;
372: else {
373: fout.write(buf, 0, size);
374: return;
375: }
376: } while (size < bufsize);
377: fout.write(buf);
378: bufsize *= 2;
379: }
380:
381: throw new IOException("too much data");
382: }
383: }
|