Package com.intellij.util.lang

Source Code of com.intellij.util.lang.JarLoader$MyResource

/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.intellij.util.lang;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.TimedComputable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Resource;

import java.io.*;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

class JarLoader extends Loader {
  private final URL myURL;
  private SoftReference<JarMemoryLoader> myMemoryLoader;
  private final boolean myCanLockJar;
  private static final boolean myDebugTime = false;

  private static final Logger LOG = Logger.getInstance(JarLoader.class);

  private final TimedComputable<ZipFile> myZipFileRef = new TimedComputable<ZipFile>(null) {
    @NotNull
    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);
      }
    }
  };

  @NonNls private static final String JAR_PROTOCOL = "jar";
  @NonNls private static final String FILE_PROTOCOL = "file";
  private static final long NS_THRESHOLD = 10000000;

  JarLoader(URL url, boolean canLockJar) throws IOException {
    super(new URL(JAR_PROTOCOL, "", -1, url + "!/"));
    myURL = url;
    myCanLockJar = canLockJar;
  }

  void preLoadClasses() {
    ZipFile zipFile = null;
    try {
      zipFile = acquireZipFile();
      if (zipFile == null) return;
      try {
        File file = new File(zipFile.getName());
        myMemoryLoader = new SoftReference<JarMemoryLoader>(JarMemoryLoader.load(file, getBaseURL()));
      }
      catch (Exception e) {
        LOG.error(e);
      }
    }
    catch (Exception e) {
      // it happens :) eg tools.jar under MacOS
    }
    finally {
      try {
        releaseZipFile(zipFile);
      }
      catch (IOException ignore) {

      }
    }
  }

  @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 (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;
  }

  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
  Resource getResource(String name, boolean flag) {
    final long started = myDebugTime ? System.nanoTime():0;
    if (myMemoryLoader != null) {
      JarMemoryLoader loader = myMemoryLoader.get();
      if (loader != null) {
        Resource resource = loader.getResource(name);
        if (resource != null) return resource;
      }
    }
    ZipFile file = null;
    try {
      file = acquireZipFile();
      if (file == null) return null;
      ZipEntry entry = file.getEntry(name);
      if (entry != null) return new MyResource(entry, new URL(getBaseURL(), name));
    }
    catch (Exception e) {
      return null;
    }
    finally {
      try {
        releaseZipFile(file);
      }
      catch (IOException ignored) {
      }
      final long doneFor = myDebugTime ? System.nanoTime() - started :0;
      if (doneFor > NS_THRESHOLD) {
        System.out.println(doneFor/1000000 + " ms for jar loader get resource:"+name);
      }
    }

    return null;
  }

  private class MyResource extends Resource {
    private final ZipEntry myEntry;
    private final URL myUrl;

    public MyResource(ZipEntry name, URL url) {
      myEntry = name;
      myUrl = url;
    }

    public String getName() {
      return myEntry.getName();
    }

    public URL getURL() {
      return myUrl;
    }

    public URL getCodeSourceURL() {
      return myURL;
    }

    @Nullable
    public 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;
          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;
      }
    }

    public int getContentLength() {
      return (int)myEntry.getSize();
    }
  }

  @NonNls
  public String toString() {
    return "JarLoader [" + myURL + "]";
  }
}
TOP

Related Classes of com.intellij.util.lang.JarLoader$MyResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.