< prev index next >

src/jdk.jartool/share/classes/sun/tools/jar/Main.java

Print this page




  30 import java.lang.module.InvalidModuleDescriptorException;
  31 import java.lang.module.ModuleDescriptor;
  32 import java.lang.module.ModuleDescriptor.Exports;
  33 import java.lang.module.ModuleDescriptor.Provides;
  34 import java.lang.module.ModuleDescriptor.Opens;
  35 import java.lang.module.ModuleDescriptor.Requires;
  36 import java.lang.module.ModuleDescriptor.Version;
  37 import java.lang.module.ModuleFinder;
  38 import java.lang.module.ModuleReader;
  39 import java.lang.module.ModuleReference;
  40 import java.lang.module.ResolutionException;
  41 import java.lang.module.ResolvedModule;
  42 import java.net.URI;
  43 import java.nio.ByteBuffer;
  44 import java.nio.file.Path;
  45 import java.nio.file.Files;
  46 import java.nio.file.Paths;
  47 import java.nio.file.StandardCopyOption;
  48 import java.util.*;
  49 import java.util.function.Consumer;
  50 import java.util.function.Function;
  51 import java.util.function.Supplier;
  52 import java.util.regex.Pattern;
  53 import java.util.stream.Collectors;
  54 import java.util.stream.Stream;
  55 import java.util.zip.*;
  56 import java.util.jar.*;
  57 import java.util.jar.Pack200.*;
  58 import java.util.jar.Manifest;
  59 import java.text.MessageFormat;
  60 
  61 import jdk.internal.module.Checks;
  62 import jdk.internal.module.ModuleHashes;

  63 import jdk.internal.module.ModuleInfo;
  64 import jdk.internal.module.ModuleInfoExtender;
  65 import jdk.internal.module.ModuleResolution;
  66 import jdk.internal.util.jar.JarIndex;
  67 
  68 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
  69 import static java.util.jar.JarFile.MANIFEST_NAME;
  70 import static java.util.stream.Collectors.joining;
  71 import static java.util.stream.Collectors.toSet;
  72 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
  73 
  74 /**
  75  * This class implements a simple utility for creating files in the JAR
  76  * (Java Archive) file format. The JAR format is based on the ZIP file
  77  * format, with optional meta-information stored in a MANIFEST entry.
  78  */
  79 public class Main {
  80     String program;
  81     PrintWriter out, err;
  82     String fname, mname, ename;
  83     String zname = "";
  84     String rootjar = null;
  85 
  86     private static final int BASE_VERSION = 0;
  87 
  88     private static class Entry {
  89         final String name;
  90         final File file;
  91         final boolean isDir;


1913 
1914         // Add (or replace) the Packages attribute
1915         extender.packages(packages);
1916 
1917         // --main-class
1918         if (ename != null)
1919             extender.mainClass(ename);
1920 
1921         // --module-version
1922         if (moduleVersion != null)
1923             extender.version(moduleVersion);
1924 
1925         // --hash-modules
1926         if (modulesToHash != null) {
1927             String mn = md.name();
1928             Hasher hasher = new Hasher(md, fname);
1929             ModuleHashes moduleHashes = hasher.computeHashes(mn);
1930             if (moduleHashes != null) {
1931                 extender.hashes(moduleHashes);
1932             } else {
1933                 // should it issue warning or silent?
1934                 System.out.println("warning: no module is recorded in hash in " + mn);
1935             }
1936         }
1937 
1938         if (moduleResolution.value() != 0) {
1939             extender.moduleResolution(moduleResolution);
1940         }
1941 
1942         extender.write(baos);
1943         return baos.toByteArray();
1944     }
1945 
1946     /**
1947      * Compute and record hashes
1948      */
1949     private class Hasher {

1950         final ModuleFinder finder;
1951         final Map<String, Path> moduleNameToPath;
1952         final Set<String> modules;
1953         final Configuration configuration;
1954         Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
1955             // Create a module finder that finds the modular JAR
1956             // being created/updated
1957             URI uri = Paths.get(fname).toUri();
1958             ModuleReference mref = new ModuleReference(descriptor, uri) {
1959                 @Override
1960                 public ModuleReader open() {
1961                     throw new UnsupportedOperationException("should not reach here");
1962                 }
1963             };
1964 
1965             // Compose a module finder with the module path and
1966             // the modular JAR being created or updated
1967             this.finder = ModuleFinder.compose(moduleFinder,
1968                 new ModuleFinder() {
1969                     @Override
1970                     public Optional<ModuleReference> find(String name) {
1971                         if (descriptor.name().equals(name))
1972                             return Optional.of(mref);
1973                         else
1974                             return Optional.empty();
1975                     }
1976 
1977                     @Override
1978                     public Set<ModuleReference> findAll() {
1979                         return Collections.singleton(mref);
1980                     }
1981                 });
1982 
1983             // Determine the modules that matches the modulesToHash pattern
1984             this.modules = moduleFinder.findAll().stream()
1985                 .map(moduleReference -> moduleReference.descriptor().name())
1986                 .filter(mn -> modulesToHash.matcher(mn).find())
1987                 .collect(Collectors.toSet());
1988 
1989             // a map from a module name to Path of the modular JAR
1990             this.moduleNameToPath = moduleFinder.findAll().stream()
1991                 .map(ModuleReference::descriptor)
1992                 .map(ModuleDescriptor::name)
1993                 .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn)));














1994 
1995             Configuration config = null;
1996             try {
1997                 config = Configuration.empty()
1998                     .resolveRequires(ModuleFinder.ofSystem(), finder, modules);
1999             } catch (ResolutionException e) {
2000                 // should it throw an error?  or emit a warning
2001                 System.out.println("warning: " + e.getMessage());
2002             }
2003             this.configuration = config;
2004         }
2005 
2006         /**
2007          * Compute hashes of the modules that depend upon the specified


2008          * module directly or indirectly.
2009          */
2010         ModuleHashes computeHashes(String name) {
2011             // the transposed graph includes all modules in the resolved graph
2012             Map<String, Set<String>> graph = transpose();
2013 
2014             // find the modules that transitively depend upon the specified name
2015             Deque<String> deque = new ArrayDeque<>();
2016             deque.add(name);
2017             Set<String> mods = visitNodes(graph, deque);
2018 
2019             // filter modules matching the pattern specified in --hash-modules,
2020             // as well as the modular jar file that is being created / updated
2021             Map<String, Path> modulesForHash = mods.stream()
2022                 .filter(mn -> !mn.equals(name) && modules.contains(mn))
2023                 .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get));
2024 
2025             if (modulesForHash.isEmpty())
2026                 return null;
2027 
2028             return ModuleHashes.generate(modulesForHash, "SHA-256");
2029         }
2030 
2031         /**
2032          * Returns all nodes traversed from the given roots.
2033          */
2034         private Set<String> visitNodes(Map<String, Set<String>> graph,
2035                                        Deque<String> roots) {
2036             Set<String> visited = new HashSet<>();
2037             while (!roots.isEmpty()) {
2038                 String mn = roots.pop();
2039                 if (!visited.contains(mn)) {
2040                     visited.add(mn);
2041 
2042                     // the given roots may not be part of the graph
2043                     if (graph.containsKey(mn)) {
2044                         for (String dm : graph.get(mn)) {
2045                             if (!visited.contains(dm))
2046                                 roots.push(dm);
2047                         }
2048                     }
2049                 }
2050             }
2051             return visited;
2052         }
2053 
2054         /**
2055          * Returns a transposed graph from the resolved module graph.
2056          */
2057         private Map<String, Set<String>> transpose() {
2058             Map<String, Set<String>> transposedGraph = new HashMap<>();
2059             Deque<String> deque = new ArrayDeque<>(modules);
2060 
2061             Set<String> visited = new HashSet<>();
2062             while (!deque.isEmpty()) {
2063                 String mn = deque.pop();
2064                 if (!visited.contains(mn)) {
2065                     visited.add(mn);
2066 
2067                     // add an empty set
2068                     transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>());
2069 
2070                     ResolvedModule resolvedModule = configuration.findModule(mn).get();
2071                     for (ResolvedModule dm : resolvedModule.reads()) {
2072                         String name = dm.name();
2073                         if (!visited.contains(name)) {
2074                             deque.push(name);
2075                         }
2076                         // reverse edge
2077                         transposedGraph.computeIfAbsent(name, _k -> new HashSet<>())
2078                                        .add(mn);
2079                     }
2080                 }
2081             }
2082             return transposedGraph;
2083         }
2084 
2085         private Path moduleToPath(String name) {
2086             ModuleReference mref = moduleFinder.find(name).orElseThrow(
2087                 () -> new InternalError(formatMsg2("error.hash.dep",name , name)));
2088 
2089             URI uri = mref.location().get();
2090             Path path = Paths.get(uri);
2091             String fn = path.getFileName().toString();
2092             if (!fn.endsWith(".jar")) {
2093                 throw new UnsupportedOperationException(path + " is not a modular JAR");
2094             }
2095             return path;
2096         }
2097     }
2098 }


  30 import java.lang.module.InvalidModuleDescriptorException;
  31 import java.lang.module.ModuleDescriptor;
  32 import java.lang.module.ModuleDescriptor.Exports;
  33 import java.lang.module.ModuleDescriptor.Provides;
  34 import java.lang.module.ModuleDescriptor.Opens;
  35 import java.lang.module.ModuleDescriptor.Requires;
  36 import java.lang.module.ModuleDescriptor.Version;
  37 import java.lang.module.ModuleFinder;
  38 import java.lang.module.ModuleReader;
  39 import java.lang.module.ModuleReference;
  40 import java.lang.module.ResolutionException;
  41 import java.lang.module.ResolvedModule;
  42 import java.net.URI;
  43 import java.nio.ByteBuffer;
  44 import java.nio.file.Path;
  45 import java.nio.file.Files;
  46 import java.nio.file.Paths;
  47 import java.nio.file.StandardCopyOption;
  48 import java.util.*;
  49 import java.util.function.Consumer;

  50 import java.util.function.Supplier;
  51 import java.util.regex.Pattern;
  52 import java.util.stream.Collectors;
  53 import java.util.stream.Stream;
  54 import java.util.zip.*;
  55 import java.util.jar.*;
  56 import java.util.jar.Pack200.*;
  57 import java.util.jar.Manifest;
  58 import java.text.MessageFormat;
  59 
  60 import jdk.internal.module.Checks;
  61 import jdk.internal.module.ModuleHashes;
  62 import jdk.internal.module.ModuleHashesBuilder;
  63 import jdk.internal.module.ModuleInfo;
  64 import jdk.internal.module.ModuleInfoExtender;
  65 import jdk.internal.module.ModuleResolution;
  66 import jdk.internal.util.jar.JarIndex;
  67 
  68 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
  69 import static java.util.jar.JarFile.MANIFEST_NAME;
  70 import static java.util.stream.Collectors.joining;

  71 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
  72 
  73 /**
  74  * This class implements a simple utility for creating files in the JAR
  75  * (Java Archive) file format. The JAR format is based on the ZIP file
  76  * format, with optional meta-information stored in a MANIFEST entry.
  77  */
  78 public class Main {
  79     String program;
  80     PrintWriter out, err;
  81     String fname, mname, ename;
  82     String zname = "";
  83     String rootjar = null;
  84 
  85     private static final int BASE_VERSION = 0;
  86 
  87     private static class Entry {
  88         final String name;
  89         final File file;
  90         final boolean isDir;


1912 
1913         // Add (or replace) the Packages attribute
1914         extender.packages(packages);
1915 
1916         // --main-class
1917         if (ename != null)
1918             extender.mainClass(ename);
1919 
1920         // --module-version
1921         if (moduleVersion != null)
1922             extender.version(moduleVersion);
1923 
1924         // --hash-modules
1925         if (modulesToHash != null) {
1926             String mn = md.name();
1927             Hasher hasher = new Hasher(md, fname);
1928             ModuleHashes moduleHashes = hasher.computeHashes(mn);
1929             if (moduleHashes != null) {
1930                 extender.hashes(moduleHashes);
1931             } else {
1932                 warn("warning: no module is recorded in hash in " + mn);

1933             }
1934         }
1935 
1936         if (moduleResolution.value() != 0) {
1937             extender.moduleResolution(moduleResolution);
1938         }
1939 
1940         extender.write(baos);
1941         return baos.toByteArray();
1942     }
1943 
1944     /**
1945      * Compute and record hashes
1946      */
1947     private class Hasher {
1948         final ModuleHashesBuilder hashesBuilder;
1949         final ModuleFinder finder;

1950         final Set<String> modules;

1951         Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
1952             // Create a module finder that finds the modular JAR
1953             // being created/updated
1954             URI uri = Paths.get(fname).toUri();
1955             ModuleReference mref = new ModuleReference(descriptor, uri) {
1956                 @Override
1957                 public ModuleReader open() {
1958                     throw new UnsupportedOperationException("should not reach here");
1959                 }
1960             };
1961 
1962             // Compose a module finder with the module path and
1963             // the modular JAR being created or updated
1964             this.finder = ModuleFinder.compose(moduleFinder,
1965                 new ModuleFinder() {
1966                     @Override
1967                     public Optional<ModuleReference> find(String name) {
1968                         if (descriptor.name().equals(name))
1969                             return Optional.of(mref);
1970                         else
1971                             return Optional.empty();
1972                     }
1973 
1974                     @Override
1975                     public Set<ModuleReference> findAll() {
1976                         return Collections.singleton(mref);
1977                     }
1978                 });
1979 
1980             // Determine the modules that matches the pattern {@code modulesToHash}
1981             Set<String> roots = finder.findAll().stream()
1982                 .map(ref -> ref.descriptor().name())
1983                 .filter(mn -> modulesToHash.matcher(mn).find())
1984                 .collect(Collectors.toSet());
1985 
1986             // use system module path unless it creates a modular JAR for
1987             // a module that is present in the system image e.g. upgradeable
1988             // module
1989             ModuleFinder system;
1990             String name = descriptor.name();
1991             if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) {
1992                 system = ModuleFinder.of();
1993             } else {
1994                 system = ModuleFinder.ofSystem();
1995             }
1996             // get a resolved module graph
1997             Configuration config =
1998                 Configuration.empty().resolveRequires(system, finder, roots);
1999 
2000             // filter modules resolved from the system module finder
2001             this.modules = config.modules().stream()
2002                 .map(ResolvedModule::name)
2003                 .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent())
2004                 .collect(Collectors.toSet());
2005 
2006             this.hashesBuilder = new ModuleHashesBuilder(config, modules);








2007         }
2008 
2009         /**
2010          * Compute hashes of the specified module.
2011          *
2012          * It records the hashing modules that depend upon the specified
2013          * module directly or indirectly.
2014          */
2015         ModuleHashes computeHashes(String name) {
2016             if (hashesBuilder == null)














2017                 return null;
2018 
2019             return hashesBuilder.computeHashes(Set.of(name)).get(name);



































































2020         }
2021     }
2022 }
< prev index next >