All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.util.lang.JarLoader Maven / Gradle / Ivy

There is a newer version: 2.1.0-Beta1-1.0.25
Show newest version
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.util.lang;

import com.intellij.openapi.diagnostic.LoggerRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.jar.Attributes;

public class JarLoader extends Loader {
  @SuppressWarnings("unchecked")
  private static final Map.Entry[] PACKAGE_FIELDS = new Map.Entry[]{
    new AbstractMap.SimpleImmutableEntry<>(Attribute.SPEC_TITLE, Attributes.Name.SPECIFICATION_TITLE),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.SPEC_VERSION, Attributes.Name.SPECIFICATION_VERSION),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.SPEC_VENDOR, Attributes.Name.SPECIFICATION_VENDOR),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.CLASS_PATH, Attributes.Name.CLASS_PATH),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.IMPL_TITLE, Attributes.Name.IMPLEMENTATION_TITLE),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.IMPL_VERSION, Attributes.Name.IMPLEMENTATION_VERSION),
    new AbstractMap.SimpleImmutableEntry<>(Attribute.IMPL_VENDOR, Attributes.Name.IMPLEMENTATION_VENDOR)
  };

  protected final ClassPath configuration;
  final URL url;
  protected final ResourceFile zipFile;
  private volatile Map attributes;

  JarLoader(@NotNull Path file, @NotNull ClassPath configuration, @NotNull ResourceFile zipFile) throws IOException {
    super(file);

    this.configuration = configuration;
    this.zipFile = zipFile;
    url = new URL("jar", "", -1, fileToUri(file) + "!/");
  }

  @Override
  public final Map getAttributes() throws IOException {
    return loadManifestAttributes(zipFile);
  }

  @Override
  final @Nullable Class findClass(@NotNull String fileName, String className, @NotNull ClassPath.ClassDataConsumer classConsumer) throws IOException {
    return zipFile.findClass(fileName, className, this, classConsumer);
  }

  // Path.toUri is broken — do not use it
  public static @NotNull URI fileToUri(@NotNull Path file) {
    String path = file.toString().replace(File.separatorChar, '/');
    if (!path.startsWith("/")) {
      path = '/' + path;
    }
    else if (path.startsWith("//")) {
      path = "//" + path;
    }

    try {
      return new URI("file", null, path, null);
    }
    catch (URISyntaxException e) {
      throw new IllegalArgumentException(path, e);
    }
  }

  final @Nullable String getClassPathManifestAttribute() throws IOException {
    return loadManifestAttributes(zipFile).get(Attribute.CLASS_PATH);
  }

  private static @NotNull Map getAttributes(@NotNull Attributes attributes) {
    if (attributes.isEmpty()) {
      return Collections.emptyMap();
    }

    Map map = null;
    for (Map.Entry p : PACKAGE_FIELDS) {
      String value = attributes.getValue(p.getValue());
      if (value != null) {
        if (map == null) {
          map = new EnumMap<>(Loader.Attribute.class);
        }
        map.put(p.getKey(), value);
      }
    }
    return map == null ? Collections.emptyMap() : map;
  }

  private @NotNull Map loadManifestAttributes(@NotNull ResourceFile resourceFile) throws IOException {
    Map result = attributes;
    if (result != null) {
      return result;
    }

    synchronized (this) {
      result = attributes;
      if (result != null) {
        return result;
      }

      result = configuration.getManifestData(path);
      if (result == null) {
        Attributes manifestAttributes = resourceFile.loadManifestAttributes();
        result = manifestAttributes == null ? Collections.emptyMap() : getAttributes(manifestAttributes);
        configuration.cacheManifestData(path, result);
      }
      attributes = result;
    }
    return result;
  }

  @Override
  public final @NotNull ClasspathCache.IndexRegistrar buildData() throws IOException {
    return zipFile.buildClassPathCacheData();
  }

  @Override
  final @Nullable Resource getResource(@NotNull String name) {
    try {
      return zipFile.getResource(name, this);
    }
    catch (IOException e) {
      error("url: " + path, e);
      return null;
    }
  }

  @Override
  void processResources(@NotNull String dir,
                        @NotNull Predicate fileNameFilter,
                        @NotNull BiConsumer consumer) throws IOException {
    zipFile.processResources(dir, fileNameFilter, consumer);
  }

  protected final void error(@NotNull String message, @NotNull Throwable t) {
    LoggerRt logger = LoggerRt.getInstance(JarLoader.class);
    if (configuration.errorOnMissingJar) {
      logger.error(message, t);
    }
    else {
      logger.warn(message, t);
    }
  }

  @Override
  public final String toString() {
    return "JarLoader [" + path + "]";
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy