package jetbrains.mps.core.tool.environment.classloading; /*Generated by MPS */ import org.jetbrains.annotations.NonNls; import java.net.URL; import java.util.zip.ZipFile; import org.jetbrains.annotations.NotNull; import java.io.IOException; import org.jetbrains.annotations.Nullable; import jetbrains.mps.core.tool.environment.common.FileUtil; import java.io.File; import java.io.FileNotFoundException; import java.util.Enumeration; import java.util.zip.ZipEntry; import java.io.InputStream; import java.io.FilterInputStream; /*package*/ class JarLoader extends Loader { private static final boolean myDebugTime = false; @NonNls private static final String JAR_PROTOCOL = "jar"; @NonNls private static final String FILE_PROTOCOL = "file"; private static final long NS_THRESHOLD = 10000000; private final URL myURL; private final boolean myCanLockJar; private final TimedComputable<ZipFile> myZipFileRef = new TimedComputable<ZipFile>() { @NotNull @Override protected ZipFile calc() { try { final ZipFile zipFile = doGetZipFile(); if (zipFile == null) { throw new RuntimeException("Can't load zip file"); } return zipFile; } catch (IOException e) { throw new RuntimeException(e); } } }; /*package*/ JarLoader(URL url, boolean canLockJar) throws IOException { super(new URL(JarLoader.JAR_PROTOCOL, "", -1, url + "!/")); myURL = url; myCanLockJar = canLockJar; } @Nullable private ZipFile acquireZipFile() throws IOException { if (myCanLockJar) { return myZipFileRef.acquire(); } return doGetZipFile(); } private void releaseZipFile(final ZipFile zipFile) throws IOException { if (myCanLockJar) { myZipFileRef.release(); } else if (zipFile != null) { zipFile.close(); } } @Nullable private ZipFile doGetZipFile() throws IOException { if (JarLoader.FILE_PROTOCOL.equals(myURL.getProtocol())) { String s = FileUtil.unquote(myURL.getFile()); if (!(new File(s).exists())) { throw new FileNotFoundException(s); } else { return new ZipFile(s); } } return null; } @Override /*package*/ void dispose() { myZipFileRef.dispose(); } @Override /*package*/ void buildCache(final ClasspathCache cache) throws IOException { ZipFile zipFile = null; try { zipFile = acquireZipFile(); if (zipFile == null) { return; } final Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry zipEntry = entries.nextElement(); cache.addResourceEntry(zipEntry.getName(), this); } } finally { releaseZipFile(zipFile); } } @Nullable @Override /*package*/ Resource getResource(String name, boolean flag) { final long started = (JarLoader.myDebugTime ? System.nanoTime() : 0); ZipFile file = null; try { file = acquireZipFile(); if (file == null) { return null; } ZipEntry entry = file.getEntry(name); if (entry != null) { return new JarLoader.MyResource(entry, new URL(getBaseURL(), name)); } } catch (Exception e) { return null; } finally { try { releaseZipFile(file); } catch (IOException ignored) { } final long doneFor = (JarLoader.myDebugTime ? System.nanoTime() - started : 0); if (doneFor > JarLoader.NS_THRESHOLD) { System.out.println(doneFor / 1000000 + " ms for jar loader get resource:" + name); } } return null; } @NonNls @Override public String toString() { return "JarLoader [" + myURL + "]"; } private class MyResource extends Resource { private final ZipEntry myEntry; private final URL myUrl; public MyResource(ZipEntry name, URL url) { myEntry = name; myUrl = url; } @Override public URL getURL() { return myUrl; } @Override protected InputStream getInputStream() throws IOException { final boolean[] wasReleased = {false}; ZipFile file = null; try { file = acquireZipFile(); if (file == null) { releaseZipFile(file); return null; } final InputStream inputStream = file.getInputStream(myEntry); if (inputStream == null) { releaseZipFile(file); return null; // if entry was not found } final ZipFile finalFile = file; return new FilterInputStream(inputStream) { private boolean myClosed = false; @Override public void close() throws IOException { super.close(); if (!(myClosed)) { releaseZipFile(finalFile); } myClosed = true; wasReleased[0] = true; } }; } catch (IOException e) { e.printStackTrace(); releaseZipFile(file); assert !(wasReleased[0]); return null; } } @Override protected int getContentLength() { return (int) myEntry.getSize(); } } }