< prev index next >

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

Print this page




  30 import java.lang.module.ModuleDescriptor;
  31 import java.lang.module.ModuleDescriptor.Exports;
  32 import java.lang.module.ModuleDescriptor.Provides;
  33 import java.lang.module.ModuleDescriptor.Opens;
  34 import java.lang.module.ModuleDescriptor.Requires;
  35 import java.lang.module.ModuleDescriptor.Version;
  36 import java.lang.module.ModuleFinder;
  37 import java.lang.module.ModuleReader;
  38 import java.lang.module.ModuleReference;
  39 import java.lang.module.ResolutionException;
  40 import java.lang.module.ResolvedModule;
  41 import java.net.URI;
  42 import java.nio.ByteBuffer;
  43 import java.nio.file.Path;
  44 import java.nio.file.Files;
  45 import java.nio.file.Paths;
  46 import java.nio.file.StandardCopyOption;
  47 import java.util.*;
  48 import java.util.function.Consumer;
  49 import java.util.function.Function;
  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.misc.JavaLangModuleAccess;
  61 import jdk.internal.misc.SharedSecrets;
  62 import jdk.internal.module.Checks;
  63 import jdk.internal.module.ModuleHashes;

  64 import jdk.internal.module.ModuleInfoExtender;

  65 import jdk.internal.util.jar.JarIndex;
  66 
  67 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
  68 import static java.util.jar.JarFile.MANIFEST_NAME;
  69 import static java.util.stream.Collectors.joining;
  70 import static java.util.stream.Collectors.toSet;
  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
  79 class Main {
  80     String program;
  81     PrintWriter out, err;
  82     String fname, mname, ename;
  83     String zname = "";
  84     String rootjar = null;


 207      */
 208     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
 209 
 210     /* To support additional GNU Style informational options */
 211     enum Info {
 212         HELP(GNUStyleOptions::printHelp),
 213         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
 214         USAGE_SUMMARY(GNUStyleOptions::printUsageSummary),
 215         VERSION(GNUStyleOptions::printVersion);
 216 
 217         private Consumer<PrintWriter> printFunction;
 218         Info(Consumer<PrintWriter> f) { this.printFunction = f; }
 219         void print(PrintWriter out) { printFunction.accept(out); }
 220     };
 221     Info info;
 222 
 223     /* Modular jar related options */
 224     boolean printModuleDescriptor;
 225     Version moduleVersion;
 226     Pattern modulesToHash;

 227     ModuleFinder moduleFinder = ModuleFinder.of();
 228 
 229     private static final String MODULE_INFO = "module-info.class";
 230 
 231     static final String MANIFEST_DIR = "META-INF/";
 232     static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
 233     static final String VERSION = "1.0";
 234 
 235     private static ResourceBundle rsrc;
 236 
 237     /**
 238      * If true, maintain compatibility with JDK releases prior to 6.0 by
 239      * timestamping extracted files with the time at which they are extracted.
 240      * Default is to use the time given in the archive.
 241      */
 242     private static final boolean useExtractionTime =
 243         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
 244 
 245     /**
 246      * Initialize ResourceBundle


1982         try (BufferedInputStream bis = new BufferedInputStream(fis);
1983              ZipInputStream zis = new ZipInputStream(bis)) {
1984 
1985             ZipEntry e;
1986             while ((e = zis.getNextEntry()) != null) {
1987                 if (e.getName().equals(MODULE_INFO)) {
1988                     printModuleDescriptor(zis);
1989                     return true;
1990                 }
1991             }
1992         }
1993         return false;
1994     }
1995 
1996     static <T> String toString(Collection<T> set) {
1997         if (set.isEmpty()) { return ""; }
1998         return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
1999                   .collect(joining(" "));
2000     }
2001 
2002     private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
2003 
2004     private void printModuleDescriptor(InputStream entryInputStream)
2005         throws IOException
2006     {
2007         ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);



2008         StringBuilder sb = new StringBuilder();
2009         sb.append("\n");
2010         if (md.isOpen())
2011             sb.append("open ");
2012         sb.append(md.toNameAndVersion());
2013 
2014         md.requires().stream()
2015             .sorted(Comparator.comparing(Requires::name))
2016             .forEach(r -> {
2017                 sb.append("\n  requires ");
2018                 if (!r.modifiers().isEmpty())
2019                     sb.append(toString(r.modifiers())).append(" ");
2020                 sb.append(r.name());
2021             });
2022 
2023         md.uses().stream().sorted()
2024             .forEach(p -> sb.append("\n  uses ").append(p));
2025 
2026         md.exports().stream()
2027             .sorted(Comparator.comparing(Exports::source))


2034         Set<String> concealed = new HashSet<>(md.packages());
2035         md.exports().stream().map(Exports::source).forEach(concealed::remove);
2036         md.opens().stream().map(Opens::source).forEach(concealed::remove);
2037         concealed.stream().sorted()
2038             .forEach(p -> sb.append("\n  contains ").append(p));
2039 
2040         md.provides().stream()
2041             .sorted(Comparator.comparing(Provides::service))
2042             .forEach(p -> sb.append("\n  provides ").append(p.service())
2043                             .append(" with ")
2044                             .append(toString(p.providers())));
2045 
2046         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
2047 
2048         md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
2049 
2050         md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
2051 
2052         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
2053 
2054         JLMA.hashes(md).ifPresent(hashes ->
2055                 hashes.names().stream().sorted().forEach(
2056                     mod -> sb.append("\n  hashes ").append(mod).append(" ")
2057                              .append(hashes.algorithm()).append(" ")
2058                              .append(hashes.hashFor(mod))));

2059 
2060         output(sb.toString());
2061     }
2062 








2063     private static String toBinaryName(String classname) {
2064         return (classname.replace('.', '/')) + ".class";
2065     }
2066 
2067     /* A module must have the implementation class of the services it 'provides'. */
2068     private boolean checkServices(byte[] moduleInfoBytes)
2069         throws IOException
2070     {
2071         ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
2072         Set<String> missing = md.provides()
2073                                 .stream()
2074                                 .map(Provides::providers)
2075                                 .flatMap(List::stream)
2076                                 .filter(p -> !jarEntries.contains(toBinaryName(p)))
2077                                 .collect(Collectors.toSet());
2078         if (missing.size() > 0) {
2079             missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s)));
2080             return false;
2081         }
2082         return true;


2203 
2204         // --module-version
2205         if (moduleVersion != null)
2206             extender.version(moduleVersion);
2207         else if (rootDescriptor.version().isPresent())
2208             extender.version(rootDescriptor.version().get());
2209 
2210         // --hash-modules
2211         if (modulesToHash != null) {
2212             String mn = md.name();
2213             Hasher hasher = new Hasher(md, fname);
2214             ModuleHashes moduleHashes = hasher.computeHashes(mn);
2215             if (moduleHashes != null) {
2216                 extender.hashes(moduleHashes);
2217             } else {
2218                 // should it issue warning or silent?
2219                 System.out.println("warning: no module is recorded in hash in " + mn);
2220             }
2221         }
2222 




2223         extender.write(baos);
2224         return baos.toByteArray();
2225     }
2226 
2227     /**
2228      * Compute and record hashes
2229      */
2230     private class Hasher {
2231         final ModuleFinder finder;
2232         final Map<String, Path> moduleNameToPath;
2233         final Set<String> modules;
2234         final Configuration configuration;
2235         Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
2236             // Create a module finder that finds the modular JAR
2237             // being created/updated
2238             URI uri = Paths.get(fname).toUri();
2239             ModuleReference mref = new ModuleReference(descriptor, uri,
2240                 new Supplier<>() {
2241                     @Override
2242                     public ModuleReader get() {
2243                         throw new UnsupportedOperationException("should not reach here");
2244                     }
2245                 });
2246 
2247             // Compose a module finder with the module path and
2248             // the modular JAR being created or updated
2249             this.finder = ModuleFinder.compose(moduleFinder,
2250                 new ModuleFinder() {
2251                     @Override
2252                     public Optional<ModuleReference> find(String name) {
2253                         if (descriptor.name().equals(name))
2254                             return Optional.of(mref);
2255                         else
2256                             return Optional.empty();
2257                     }
2258 
2259                     @Override
2260                     public Set<ModuleReference> findAll() {
2261                         return Collections.singleton(mref);
2262                     }
2263                 });
2264 
2265             // Determine the modules that matches the modulesToHash pattern




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

  50 import java.util.regex.Pattern;
  51 import java.util.stream.Collectors;
  52 import java.util.stream.Stream;
  53 import java.util.zip.*;
  54 import java.util.jar.*;
  55 import java.util.jar.Pack200.*;
  56 import java.util.jar.Manifest;
  57 import java.text.MessageFormat;
  58 


  59 import jdk.internal.module.Checks;
  60 import jdk.internal.module.ModuleHashes;
  61 import jdk.internal.module.ModuleInfo;
  62 import jdk.internal.module.ModuleInfoExtender;
  63 import jdk.internal.module.ModuleResolution;
  64 import jdk.internal.util.jar.JarIndex;
  65 
  66 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
  67 import static java.util.jar.JarFile.MANIFEST_NAME;
  68 import static java.util.stream.Collectors.joining;
  69 import static java.util.stream.Collectors.toSet;
  70 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
  71 
  72 /**
  73  * This class implements a simple utility for creating files in the JAR
  74  * (Java Archive) file format. The JAR format is based on the ZIP file
  75  * format, with optional meta-information stored in a MANIFEST entry.
  76  */
  77 public
  78 class Main {
  79     String program;
  80     PrintWriter out, err;
  81     String fname, mname, ename;
  82     String zname = "";
  83     String rootjar = null;


 206      */
 207     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
 208 
 209     /* To support additional GNU Style informational options */
 210     enum Info {
 211         HELP(GNUStyleOptions::printHelp),
 212         COMPAT_HELP(GNUStyleOptions::printCompatHelp),
 213         USAGE_SUMMARY(GNUStyleOptions::printUsageSummary),
 214         VERSION(GNUStyleOptions::printVersion);
 215 
 216         private Consumer<PrintWriter> printFunction;
 217         Info(Consumer<PrintWriter> f) { this.printFunction = f; }
 218         void print(PrintWriter out) { printFunction.accept(out); }
 219     };
 220     Info info;
 221 
 222     /* Modular jar related options */
 223     boolean printModuleDescriptor;
 224     Version moduleVersion;
 225     Pattern modulesToHash;
 226     ModuleResolution moduleResolution = new ModuleResolution(0);
 227     ModuleFinder moduleFinder = ModuleFinder.of();
 228 
 229     private static final String MODULE_INFO = "module-info.class";
 230 
 231     static final String MANIFEST_DIR = "META-INF/";
 232     static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
 233     static final String VERSION = "1.0";
 234 
 235     private static ResourceBundle rsrc;
 236 
 237     /**
 238      * If true, maintain compatibility with JDK releases prior to 6.0 by
 239      * timestamping extracted files with the time at which they are extracted.
 240      * Default is to use the time given in the archive.
 241      */
 242     private static final boolean useExtractionTime =
 243         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
 244 
 245     /**
 246      * Initialize ResourceBundle


1982         try (BufferedInputStream bis = new BufferedInputStream(fis);
1983              ZipInputStream zis = new ZipInputStream(bis)) {
1984 
1985             ZipEntry e;
1986             while ((e = zis.getNextEntry()) != null) {
1987                 if (e.getName().equals(MODULE_INFO)) {
1988                     printModuleDescriptor(zis);
1989                     return true;
1990                 }
1991             }
1992         }
1993         return false;
1994     }
1995 
1996     static <T> String toString(Collection<T> set) {
1997         if (set.isEmpty()) { return ""; }
1998         return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
1999                   .collect(joining(" "));
2000     }
2001 


2002     private void printModuleDescriptor(InputStream entryInputStream)
2003         throws IOException
2004     {
2005         ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
2006         ModuleDescriptor md = attrs.descriptor();
2007         ModuleHashes hashes = attrs.recordedHashes();
2008 
2009         StringBuilder sb = new StringBuilder();
2010         sb.append("\n");
2011         if (md.isOpen())
2012             sb.append("open ");
2013         sb.append(md.toNameAndVersion());
2014 
2015         md.requires().stream()
2016             .sorted(Comparator.comparing(Requires::name))
2017             .forEach(r -> {
2018                 sb.append("\n  requires ");
2019                 if (!r.modifiers().isEmpty())
2020                     sb.append(toString(r.modifiers())).append(" ");
2021                 sb.append(r.name());
2022             });
2023 
2024         md.uses().stream().sorted()
2025             .forEach(p -> sb.append("\n  uses ").append(p));
2026 
2027         md.exports().stream()
2028             .sorted(Comparator.comparing(Exports::source))


2035         Set<String> concealed = new HashSet<>(md.packages());
2036         md.exports().stream().map(Exports::source).forEach(concealed::remove);
2037         md.opens().stream().map(Opens::source).forEach(concealed::remove);
2038         concealed.stream().sorted()
2039             .forEach(p -> sb.append("\n  contains ").append(p));
2040 
2041         md.provides().stream()
2042             .sorted(Comparator.comparing(Provides::service))
2043             .forEach(p -> sb.append("\n  provides ").append(p.service())
2044                             .append(" with ")
2045                             .append(toString(p.providers())));
2046 
2047         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
2048 
2049         md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
2050 
2051         md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
2052 
2053         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
2054 
2055         if (hashes != null) {
2056             hashes.names().stream().sorted().forEach(
2057                     mod -> sb.append("\n  hashes ").append(mod).append(" ")
2058                              .append(hashes.algorithm()).append(" ")
2059                              .append(toHex(hashes.hashFor(mod))));
2060         }
2061 
2062         output(sb.toString());
2063     }
2064 
2065     private static String toHex(byte[] ba) {
2066         StringBuilder sb = new StringBuilder(ba.length);
2067         for (byte b: ba) {
2068             sb.append(String.format("%02x", b & 0xff));
2069         }
2070         return sb.toString();
2071     }
2072 
2073     private static String toBinaryName(String classname) {
2074         return (classname.replace('.', '/')) + ".class";
2075     }
2076 
2077     /* A module must have the implementation class of the services it 'provides'. */
2078     private boolean checkServices(byte[] moduleInfoBytes)
2079         throws IOException
2080     {
2081         ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
2082         Set<String> missing = md.provides()
2083                                 .stream()
2084                                 .map(Provides::providers)
2085                                 .flatMap(List::stream)
2086                                 .filter(p -> !jarEntries.contains(toBinaryName(p)))
2087                                 .collect(Collectors.toSet());
2088         if (missing.size() > 0) {
2089             missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s)));
2090             return false;
2091         }
2092         return true;


2213 
2214         // --module-version
2215         if (moduleVersion != null)
2216             extender.version(moduleVersion);
2217         else if (rootDescriptor.version().isPresent())
2218             extender.version(rootDescriptor.version().get());
2219 
2220         // --hash-modules
2221         if (modulesToHash != null) {
2222             String mn = md.name();
2223             Hasher hasher = new Hasher(md, fname);
2224             ModuleHashes moduleHashes = hasher.computeHashes(mn);
2225             if (moduleHashes != null) {
2226                 extender.hashes(moduleHashes);
2227             } else {
2228                 // should it issue warning or silent?
2229                 System.out.println("warning: no module is recorded in hash in " + mn);
2230             }
2231         }
2232 
2233         if (moduleResolution.value() != 0) {
2234             extender.moduleResolution(moduleResolution);
2235         }
2236 
2237         extender.write(baos);
2238         return baos.toByteArray();
2239     }
2240 
2241     /**
2242      * Compute and record hashes
2243      */
2244     private class Hasher {
2245         final ModuleFinder finder;
2246         final Map<String, Path> moduleNameToPath;
2247         final Set<String> modules;
2248         final Configuration configuration;
2249         Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
2250             // Create a module finder that finds the modular JAR
2251             // being created/updated
2252             URI uri = Paths.get(fname).toUri();
2253             ModuleReference mref = new ModuleReference(descriptor, uri) {

2254                 @Override
2255                 public ModuleReader open() {
2256                     throw new UnsupportedOperationException("should not reach here");
2257                 }
2258             };
2259 
2260             // Compose a module finder with the module path and
2261             // the modular JAR being created or updated
2262             this.finder = ModuleFinder.compose(moduleFinder,
2263                 new ModuleFinder() {
2264                     @Override
2265                     public Optional<ModuleReference> find(String name) {
2266                         if (descriptor.name().equals(name))
2267                             return Optional.of(mref);
2268                         else
2269                             return Optional.empty();
2270                     }
2271 
2272                     @Override
2273                     public Set<ModuleReference> findAll() {
2274                         return Collections.singleton(mref);
2275                     }
2276                 });
2277 
2278             // Determine the modules that matches the modulesToHash pattern


< prev index next >