/Users/lyon/j4p/src/javassist/ClassPoolTail.java
|
1 /*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2003 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
16 package javassist;
17
18 import java.io.*;
19 import java.util.zip.*;
20
21 final class ClassPathList {
22 ClassPathList next;
23 ClassPath path;
24
25 ClassPathList(ClassPath p, ClassPathList n) {
26 next = n;
27 path = p;
28 }
29 }
30
31
32 final class SystemClassPath implements ClassPath {
33 Class thisClass;
34
35 SystemClassPath() {
36 /* The value of thisClass was this.getClass() in early versions:
37 *
38 * thisClass = this.getClass();
39 *
40 * However, this made openClassfile() not search all the system
41 * class paths if javassist.jar is put in jre/lib/ext/
42 * (with JDK1.4).
43 */
44 thisClass = java.lang.Object.class;
45 }
46
47 public InputStream openClassfile(String classname) {
48 String jarname = "/" + classname.replace('.', '/') + ".class";
49 return thisClass.getResourceAsStream(jarname);
50 }
51
52 public void close() {
53 }
54
55 public String toString() {
56 return "*system class path*";
57 }
58 }
59
60
61 final class DirClassPath implements ClassPath {
62 String directory;
63
64 DirClassPath(String dirName) {
65 directory = dirName;
66 }
67
68 public InputStream openClassfile(String classname) {
69 try {
70 char sep = File.separatorChar;
71 String filename = directory + sep
72 + classname.replace('.', sep) + ".class";
73 return new FileInputStream(filename.toString());
74 } catch (FileNotFoundException e) {
75 } catch (SecurityException e) {
76 }
77 return null;
78 }
79
80 public void close() {
81 }
82
83 public String toString() {
84 return directory;
85 }
86 }
87
88
89 final class JarClassPath implements ClassPath {
90 ZipFile jarfile;
91
92 JarClassPath(String pathname) throws NotFoundException {
93 try {
94 jarfile = new ZipFile(pathname);
95 return;
96 } catch (ZipException e) {
97 } catch (IOException e) {
98 }
99 throw new NotFoundException(pathname);
100 }
101
102 public InputStream openClassfile(String classname)
103 throws NotFoundException {
104 try {
105 String jarname = classname.replace('.', '/') + ".class";
106 ZipEntry ze = jarfile.getEntry(jarname);
107 if (ze != null)
108 return jarfile.getInputStream(ze);
109 else
110 return null; // not found
111 } catch (ZipException e) {
112 } catch (IOException e) {
113 }
114 throw new NotFoundException("broken jar file?: "
115 + jarfile.getName());
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 extends ClassPool {
132 protected ClassPathList pathList;
133 private Class thisClass;
134
135 public ClassPoolTail() {
136 pathList = null;
137 thisClass = getClass();
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 byte[] write(String classname)
155 throws NotFoundException, IOException {
156 return readClassfile(classname);
157 }
158
159 public void write(String classname, DataOutputStream out)
160 throws NotFoundException, CannotCompileException, IOException {
161 byte[] b = write(classname);
162 out.write(b, 0, b.length);
163 }
164
165 public CtClass get(String classname) throws NotFoundException {
166 throw new RuntimeException("fatal error");
167 }
168
169 public CtClass makeClass(String classname) {
170 throw new RuntimeException("fatal error");
171 }
172
173 void checkClassName(String classname)
174 throws NotFoundException {
175 InputStream fin = openClassfile(classname);
176 try {
177 fin.close();
178 } catch (IOException e) { /* ignore */
179 }
180 }
181
182 public synchronized ClassPath insertClassPath(ClassPath cp) {
183 pathList = new ClassPathList(cp, pathList);
184 return cp;
185 }
186
187 public synchronized ClassPath appendClassPath(ClassPath cp) {
188 ClassPathList tail = new ClassPathList(cp, null);
189 ClassPathList list = pathList;
190 if (list == null)
191 pathList = tail;
192 else {
193 while (list.next != null)
194 list = list.next;
195
196 list.next = tail;
197 }
198
199 return cp;
200 }
201
202 public synchronized void removeClassPath(ClassPath cp) {
203 ClassPathList list = pathList;
204 if (list != null)
205 if (list.path == cp)
206 pathList = list.next;
207 else {
208 while (list.next != null)
209 if (list.next.path == cp)
210 list.next = list.next.next;
211 else
212 list = list.next;
213 }
214
215 cp.close();
216 }
217
218 public ClassPath appendSystemPath() {
219 return appendClassPath(new SystemClassPath());
220 }
221
222 public ClassPath insertClassPath(String pathname)
223 throws NotFoundException {
224 return insertClassPath(makePathObject(pathname));
225 }
226
227 public ClassPath appendClassPath(String pathname)
228 throws NotFoundException {
229 return appendClassPath(makePathObject(pathname));
230 }
231
232 private static ClassPath makePathObject(String pathname)
233 throws NotFoundException {
234 int i = pathname.lastIndexOf('.');
235 if (i >= 0) {
236 String ext = pathname.substring(i).toLowerCase();
237 if (ext.equals(".jar") || ext.equals(".zip"))
238 return new JarClassPath(pathname);
239 }
240
241 return new DirClassPath(pathname);
242 }
243
244 /**
245 * Obtains the contents of the class file for the class
246 * specified by <code>classname</code>.
247 *
248 * @param classname a fully-qualified class name
249 */
250 byte[] readClassfile(String classname)
251 throws NotFoundException, IOException {
252 InputStream fin = openClassfile(classname);
253 byte[] b;
254 try {
255 b = readStream(fin);
256 } finally {
257 fin.close();
258 }
259
260 return b;
261 }
262
263 /**
264 * Opens the class file for the class specified by
265 * <code>classname</code>.
266 *
267 * @param classname a fully-qualified class name
268 */
269 public InputStream openClassfile(String classname)
270 throws NotFoundException {
271 ClassPathList list = pathList;
272 InputStream ins = null;
273 NotFoundException error = null;
274 while (list != null) {
275 try {
276 ins = list.path.openClassfile(classname);
277 } catch (NotFoundException e) {
278 if (error == null)
279 error = e;
280 }
281
282 if (ins == null)
283 list = list.next;
284 else
285 return ins;
286 }
287
288 if (error != null)
289 throw error;
290 else
291 throw new NotFoundException(classname);
292 }
293
294 /**
295 * Reads an input stream until it reaches the end.
296 *
297 * @return the contents of that input stream
298 */
299 public static byte[] readStream(InputStream fin) throws IOException {
300 byte[][] bufs = new byte[8][];
301 int bufsize = 4096;
302
303 for (int i = 0; i < 8; ++i) {
304 bufs[i] = new byte[bufsize];
305 int size = 0;
306 int len = 0;
307 do {
308 len = fin.read(bufs[i], size, bufsize - size);
309 if (len >= 0)
310 size += len;
311 else {
312 byte[] result = new byte[bufsize - 4096 + size];
313 int s = 0;
314 for (int j = 0; j < i; ++j) {
315 System.arraycopy(bufs[j], 0, result, s, s + 4096);
316 s = s + s + 4096;
317 }
318
319 System.arraycopy(bufs[i], 0, result, s, size);
320 return result;
321 }
322 } while (size < bufsize);
323 bufsize *= 2;
324 }
325
326 throw new IOException("too much data");
327 }
328 }
329