/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