1 12 package org.eclipse.jdt.apt.core.internal; 13 14 import java.io.ByteArrayOutputStream ; 15 import java.io.File ; 16 import java.io.IOException ; 17 import java.io.InputStream ; 18 import java.net.URL ; 19 import java.util.ArrayList ; 20 import java.util.Enumeration ; 21 import java.util.LinkedHashSet ; 22 import java.util.LinkedList ; 23 import java.util.List ; 24 import java.util.Set ; 25 import java.util.jar.Attributes ; 26 import java.util.jar.JarFile ; 27 import java.util.jar.Manifest ; 28 import java.util.zip.ZipEntry ; 29 30 31 32 42 public class JarClassLoader extends ClassLoader { 43 44 private List <JarFile > _jars; 46 private final LinkedHashSet <File > _files; 47 private List <JarCLInputStream> _openStreams = new LinkedList <JarCLInputStream>(); 48 private boolean _open = true; 49 50 public JarClassLoader(List <File > jarFiles, final ClassLoader parent) { 51 super(parent); 52 _files = new LinkedHashSet <File >(jarFiles); 54 for (File f : jarFiles) { 55 _recursiveGetManifestJars(f, _files); 56 } 57 open(); 58 } 59 60 private void open() { 61 _jars = new ArrayList <JarFile >(_files.size()); 63 for (File f : _files) { 64 try { 65 JarFile jar = new JarFile (f); 66 _jars.add(jar); 67 } 68 catch (IOException ioe) { 69 AptPlugin.log(ioe, "Unable to create JarFile for file: " + f); } 71 } 72 } 73 74 public synchronized void close() { 75 if (! _open) return; 76 _open = false; 77 78 for (JarCLInputStream st : _openStreams) { 79 try { 80 st.close(); 81 } 82 catch (IOException ioe) { 83 AptPlugin.log(ioe, "Failed to close stream"); } 85 } 86 _openStreams = null; 87 88 for (JarFile jar : _jars) { 89 try { 90 jar.close(); 91 } 92 catch (IOException ioe) { 93 AptPlugin.log(ioe, "Failed to close jar: " + jar); } 95 } 96 _jars = null; 97 } 98 99 private InputStream openInputStream(InputStream in) { 100 JarCLInputStream result = new JarCLInputStream(in); 101 _openStreams.add(result); 102 return in; 103 } 104 105 private synchronized void closeInputStream(JarCLInputStream in) { 106 if (_open) 107 _openStreams.remove(in); 108 } 109 110 @Override 111 protected synchronized Class <?> findClass(String name) throws ClassNotFoundException { 112 if (!_open) 113 throw new ClassNotFoundException ("Classloader closed: " + name); 115 byte[] b = loadClassData(name); 116 if (b == null) { 117 throw new ClassNotFoundException ("Could not find class " + name); } 119 Class <?> clazz = defineClass(name, b, 0, b.length); 120 String pkgName = getPackageName(name); 122 if (pkgName != null) { 123 Package pkg = getPackage(pkgName); 124 if (pkg == null) { 125 definePackage(pkgName, null, null, null, null, null, null, null); 126 } 127 } 128 return clazz; 129 } 130 131 private String getPackageName(String fullyQualifiedName) { 132 int index = fullyQualifiedName.lastIndexOf('.'); 133 if (index != -1) { 134 return fullyQualifiedName.substring(0, index); 135 } 136 return null; 137 } 138 139 private byte[] loadClassData(String name) { 141 name = name.replace('.','/'); 142 InputStream input = getResourceAsStream(name + ".class"); if (input == null) 144 return null; 145 try { 146 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 147 byte[] buf = new byte[1024]; 148 int len; 149 while ((len = input.read(buf)) > 0) { 150 baos.write(buf, 0, len); 151 } 152 baos.close(); 153 return baos.toByteArray(); 154 } 155 catch (IOException ioe) { 156 return null; 157 } 158 finally { 159 try {input.close();} catch (IOException ioe) {} 160 } 161 } 162 163 @Override 164 public synchronized InputStream getResourceAsStream(String name) { 165 InputStream input = getParent().getResourceAsStream(name); 166 if (input != null) 167 return input; 168 169 if (!_open) 170 return null; 171 172 for (JarFile j : _jars) { 173 try { 174 ZipEntry entry = j.getEntry(name); 175 if (entry != null) { 176 InputStream zipInput = j.getInputStream(entry); 177 return openInputStream(zipInput); 178 } 179 } 180 catch (IOException ioe) { 181 AptPlugin.log(ioe, "Unable to get entry from jar: " + j); } 183 } 184 return null; 185 } 186 187 194 @Override 195 public URL getResource(String name) { 196 for (JarFile j : _jars) { 197 ZipEntry entry = j.getEntry(name); 198 if (entry != null) { 199 throw new UnsupportedOperationException ("getResource() not implemented: " + name); } 201 } 202 return null; 203 } 204 205 209 @Override 210 public Enumeration <URL > getResources(String name) throws IOException { 211 throw new UnsupportedOperationException ("getResources() not implemented"); } 213 214 private class JarCLInputStream extends InputStream { 215 216 private boolean _closed = false; 217 218 private final InputStream _input; 219 220 public JarCLInputStream(InputStream origInput) { 221 _input = origInput; 222 } 223 224 @Override 225 public void close() throws IOException { 226 if (_closed) { 227 return; 229 } 230 try { 231 super.close(); 232 _input.close(); 233 _closed = true; 234 } 235 finally { 236 closeInputStream(this); 237 } 238 } 239 240 @Override 241 public int read() throws IOException { 242 return _input.read(); 243 } 244 245 @Override 246 public int available() throws IOException { 247 return _input.available(); 248 } 249 250 @Override 251 public synchronized void mark(int readlimit) { 252 _input.mark(readlimit); 253 } 254 255 @Override 256 public boolean markSupported() { 257 return _input.markSupported(); 258 } 259 260 @Override 261 public int read(byte[] b, int off, int len) throws IOException { 262 return _input.read(b, off, len); 263 } 264 265 @Override 266 public int read(byte[] b) throws IOException { 267 return _input.read(b); 268 } 269 270 @Override 271 public synchronized void reset() throws IOException { 272 _input.reset(); 273 } 274 275 @Override 276 public long skip(long n) throws IOException { 277 return _input.skip(n); 278 } 279 } 280 281 285 private static void _recursiveGetManifestJars(File jarFile, Set <File > manifestJars) { 286 if (!jarFile.exists()) 287 return; 288 289 JarFile jar = null; 290 try { 291 jar = new JarFile (jarFile); 292 Manifest mf = jar.getManifest(); 293 if (mf == null) 294 return; 295 String classpath = mf.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); 296 if (classpath == null) 297 return; 298 299 File parent = jarFile.getParentFile(); 301 302 String [] rgPaths = classpath.split(" "); for (String path : rgPaths) 304 { 305 if (path.length() == 0) 306 continue; 307 File file = new File (parent, path); 308 if (!manifestJars.contains(file) && file.exists()) { 310 manifestJars.add(file); 311 _recursiveGetManifestJars(file, manifestJars); 312 } 313 } 314 } 315 catch (IOException ioe) { 316 } 317 finally { 318 if (jar != null) { 319 try {jar.close();} catch (IOException ioe) {} 320 } 321 } 322 } 323 } 324 | Popular Tags |