--- old/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java 2016-09-28 15:01:54.000000000 -0700 +++ new/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java 2016-09-28 15:01:54.000000000 -0700 @@ -25,8 +25,6 @@ package jdk.tools.jmod; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -60,7 +58,6 @@ import java.text.MessageFormat; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -80,15 +77,16 @@ import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; import java.util.stream.Collectors; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; +import jdk.internal.jmod.JmodFile; +import jdk.internal.jmod.JmodFile.Section; import jdk.internal.joptsimple.BuiltinHelpFormatter; import jdk.internal.joptsimple.NonOptionArgumentSpec; import jdk.internal.joptsimple.OptionDescriptor; @@ -250,23 +248,14 @@ } private boolean describe() throws IOException { - ZipFile zip = null; - try { - try { - zip = new ZipFile(options.jmodFile.toFile()); - } catch (IOException x) { - throw new IOException("error opening jmod file", x); - } - - try (InputStream in = Files.newInputStream(options.jmodFile)) { - boolean found = printModuleDescriptor(in); - if (!found) - throw new CommandException("err.module.descriptor.not.found"); - return found; + try (JmodFile jf = new JmodFile(options.jmodFile)) { + try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) { + ModuleDescriptor md = ModuleDescriptor.read(in); + printModuleDescriptor(md); + return true; + } catch (IOException e) { + throw new CommandException("err.module.descriptor.not.found"); } - } finally { - if (zip != null) - zip.close(); } } @@ -278,65 +267,52 @@ private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess(); - private boolean printModuleDescriptor(InputStream in) + private void printModuleDescriptor(ModuleDescriptor md) throws IOException { - final String mi = Section.CLASSES.jmodDir() + "/" + MODULE_INFO; - try (BufferedInputStream bis = new BufferedInputStream(in); - ZipInputStream zis = new ZipInputStream(bis)) { - - ZipEntry e; - while ((e = zis.getNextEntry()) != null) { - if (e.getName().equals(mi)) { - ModuleDescriptor md = ModuleDescriptor.read(zis); - StringBuilder sb = new StringBuilder(); - sb.append("\n").append(md.toNameAndVersion()); - - md.requires().stream() - .sorted(Comparator.comparing(Requires::name)) - .forEach(r -> { - sb.append("\n requires "); - if (!r.modifiers().isEmpty()) - sb.append(toString(r.modifiers())).append(" "); - sb.append(r.name()); - }); - - md.uses().stream().sorted() - .forEach(s -> sb.append("\n uses ").append(s)); - - md.exports().stream() - .sorted(Comparator.comparing(Exports::source)) - .forEach(p -> sb.append("\n exports ").append(p)); - - md.conceals().stream().sorted() - .forEach(p -> sb.append("\n conceals ").append(p)); - - md.provides().values().stream() - .sorted(Comparator.comparing(Provides::service)) - .forEach(p -> sb.append("\n provides ").append(p.service()) - .append(" with ") - .append(toString(p.providers()))); - - md.mainClass().ifPresent(v -> sb.append("\n main-class " + v)); - - md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v)); - - md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v)); - - md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v)); - - JLMA.hashes(md).ifPresent( - hashes -> hashes.names().stream().sorted().forEach( - mod -> sb.append("\n hashes ").append(mod).append(" ") - .append(hashes.algorithm()).append(" ") - .append(hashes.hashFor(mod)))); + StringBuilder sb = new StringBuilder(); + sb.append("\n").append(md.toNameAndVersion()); - out.println(sb.toString()); - return true; - } - } - } - return false; + md.requires().stream() + .sorted(Comparator.comparing(Requires::name)) + .forEach(r -> { + sb.append("\n requires "); + if (!r.modifiers().isEmpty()) + sb.append(toString(r.modifiers())).append(" "); + sb.append(r.name()); + }); + + md.uses().stream().sorted() + .forEach(s -> sb.append("\n uses ").append(s)); + + md.exports().stream() + .sorted(Comparator.comparing(Exports::source)) + .forEach(p -> sb.append("\n exports ").append(p)); + + md.conceals().stream().sorted() + .forEach(p -> sb.append("\n conceals ").append(p)); + + md.provides().values().stream() + .sorted(Comparator.comparing(Provides::service)) + .forEach(p -> sb.append("\n provides ").append(p.service()) + .append(" with ") + .append(toString(p.providers()))); + + md.mainClass().ifPresent(v -> sb.append("\n main-class " + v)); + + md.osName().ifPresent(v -> sb.append("\n operating-system-name " + v)); + + md.osArch().ifPresent(v -> sb.append("\n operating-system-architecture " + v)); + + md.osVersion().ifPresent(v -> sb.append("\n operating-system-version " + v)); + + JLMA.hashes(md).ifPresent( + hashes -> hashes.names().stream().sorted().forEach( + mod -> sb.append("\n hashes ").append(mod).append(" ") + .append(hashes.algorithm()).append(" ") + .append(hashes.hashFor(mod)))); + + out.println(sb.toString()); } private boolean create() throws IOException { @@ -347,9 +323,8 @@ Path target = options.jmodFile; Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp"); try { - try (OutputStream out = Files.newOutputStream(tempTarget); - BufferedOutputStream bos = new BufferedOutputStream(out)) { - jmod.write(bos); + try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) { + jmod.write(jos); } Files.move(tempTarget, target); } catch (Exception e) { @@ -383,19 +358,16 @@ /** * Writes the jmod to the given output stream. */ - void write(OutputStream out) throws IOException { - try (ZipOutputStream zos = new ZipOutputStream(out)) { - - // module-info.class - writeModuleInfo(zos, findPackages(classpath)); - - // classes - processClasses(zos, classpath); - - processSection(zos, Section.NATIVE_CMDS, cmds); - processSection(zos, Section.NATIVE_LIBS, libs); - processSection(zos, Section.CONFIG, configs); - } + void write(JmodOutputStream out) throws IOException { + // module-info.class + writeModuleInfo(out, findPackages(classpath)); + + // classes + processClasses(out, classpath); + + processSection(out, Section.NATIVE_CMDS, cmds); + processSection(out, Section.NATIVE_LIBS, libs); + processSection(out, Section.CONFIG, configs); } /** @@ -441,7 +413,7 @@ * then the corresponding class file attributes are added to the * module-info here. */ - void writeModuleInfo(ZipOutputStream zos, Set packages) + void writeModuleInfo(JmodOutputStream out, Set packages) throws IOException { Supplier miSupplier = newModuleInfoSupplier(); @@ -492,11 +464,7 @@ } // write the (possibly extended or modified) module-info.class - String e = Section.CLASSES.jmodDir() + "/" + MODULE_INFO; - ZipEntry ze = new ZipEntry(e); - zos.putNextEntry(ze); - extender.write(zos); - zos.closeEntry(); + out.writeEntry(extender.getBytes(), Section.CLASSES, MODULE_INFO); } } @@ -627,7 +595,7 @@ return ""; } - void processClasses(ZipOutputStream zos, List classpaths) + void processClasses(JmodOutputStream zos, List classpaths) throws IOException { if (classpaths == null) @@ -645,7 +613,7 @@ } } - void processSection(ZipOutputStream zos, Section section, List paths) + void processSection(JmodOutputStream zos, Section section, List paths) throws IOException { if (paths == null) @@ -655,11 +623,9 @@ processSection(zos, section, p); } - void processSection(ZipOutputStream zos, Section section, Path top) + void processSection(JmodOutputStream out, Section section, Path top) throws IOException { - final String prefix = section.jmodDir(); - Files.walkFileTree(top, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) @@ -667,13 +633,19 @@ { Path relPath = top.relativize(file); if (relPath.toString().equals(MODULE_INFO) - && !Section.CLASSES.equals(section)) + && !Section.CLASSES.equals(section)) warning("warn.ignore.entry", MODULE_INFO, section); if (!relPath.toString().equals(MODULE_INFO) - && !matches(relPath, excludes)) { + && !matches(relPath, excludes)) { try (InputStream in = Files.newInputStream(file)) { - writeZipEntry(zos, in, prefix, relPath.toString()); + out.writeEntry(in, section, relPath.toString()); + } catch (IOException x) { + if (x.getMessage().contains("duplicate entry")) { + warning("warn.ignore.duplicate.entry", relPath.toString(), section); + return FileVisitResult.CONTINUE; + } + throw x; } } return FileVisitResult.CONTINUE; @@ -691,36 +663,17 @@ return false; } - void writeZipEntry(ZipOutputStream zos, InputStream in, String prefix, String other) - throws IOException - { - String name = Paths.get(prefix, other).toString() - .replace(File.separatorChar, '/'); - ZipEntry ze = new ZipEntry(name); - try { - zos.putNextEntry(ze); - in.transferTo(zos); - zos.closeEntry(); - } catch (ZipException x) { - if (x.getMessage().contains("duplicate entry")) { - warning("warn.ignore.duplicate.entry", name, prefix); - return; - } - throw x; - } - } - class JarEntryConsumer implements Consumer, Predicate { - final ZipOutputStream zos; + final JmodOutputStream out; final JarFile jarfile; - JarEntryConsumer(ZipOutputStream zos, JarFile jarfile) { - this.zos = zos; + JarEntryConsumer(JmodOutputStream out, JarFile jarfile) { + this.out = out; this.jarfile = jarfile; } @Override public void accept(JarEntry je) { try (InputStream in = jarfile.getInputStream(je)) { - writeZipEntry(zos, in, Section.CLASSES.jmodDir(), je.getName()); + out.writeEntry(in, Section.CLASSES, je.getName()); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -947,29 +900,11 @@ { Path target = moduleNameToPath.get(name); Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp"); - ZipFile zip = new ZipFile(target.toFile()); try { - try (OutputStream out = Files.newOutputStream(tempTarget); - ZipOutputStream zos = new ZipOutputStream(out)) { - zip.stream().forEach(e -> { - try { - InputStream in = zip.getInputStream(e); - if (e.getName().equals(MODULE_INFO) || - e.getName().equals(Section.CLASSES.jmodDir() + "/" + MODULE_INFO)) { - ZipEntry ze = new ZipEntry(e.getName()); - ze.setTime(System.currentTimeMillis()); - zos.putNextEntry(ze); - recordHashes(in, zos, moduleHashes); - zos.closeEntry(); - } else { - zos.putNextEntry(e); - zos.write(in.readAllBytes()); - zos.closeEntry(); - } - } catch (IOException x) { - throw new UncheckedIOException(x); - } - }); + if (target.getFileName().toString().endsWith(".jmod")) { + updateJmodFile(target, tempTarget, moduleHashes); + } else { + updateModularJar(target, tempTarget, moduleHashes); } } catch (IOException|RuntimeException e) { if (Files.exists(tempTarget)) { @@ -980,13 +915,67 @@ } } throw e; - } finally { - zip.close(); } + out.println(getMessage("module.hashes.recorded", name)); Files.move(tempTarget, target, StandardCopyOption.REPLACE_EXISTING); } + private void updateModularJar(Path target, Path tempTarget, + ModuleHashes moduleHashes) + throws IOException + { + try (JarFile jf = new JarFile(target.toFile()); + OutputStream out = Files.newOutputStream(tempTarget); + JarOutputStream jos = new JarOutputStream(out)) + { + jf.stream().forEach(e -> { + try (InputStream in = jf.getInputStream(e)) { + if (e.getName().equals(MODULE_INFO)) { + // what about module-info.class in versioned entries? + ZipEntry ze = new ZipEntry(e.getName()); + ze.setTime(System.currentTimeMillis()); + jos.putNextEntry(ze); + recordHashes(in, jos, moduleHashes); + jos.closeEntry(); + } else { + jos.putNextEntry(e); + jos.write(in.readAllBytes()); + jos.closeEntry(); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + } + + private void updateJmodFile(Path target, Path tempTarget, + ModuleHashes moduleHashes) + throws IOException + { + + try (JmodFile jf = new JmodFile(target); + JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) + { + jf.stream().forEach(e -> { + try (InputStream in = jf.getInputStream(e.section(), e.name())) { + if (e.name().equals(MODULE_INFO)) { + // replace module-info.class + ModuleInfoExtender extender = + ModuleInfoExtender.newExtender(in); + extender.hashes(moduleHashes); + jos.writeEntry(extender.getBytes(), e.section(), e.name()); + } else { + jos.writeEntry(in, e); + } + } catch (IOException x) { + throw new UncheckedIOException(x); + } + }); + } + } + private Path moduleToPath(String name) { ModuleReference mref = moduleFinder.find(name).orElseThrow( () -> new InternalError("Selected module " + name + " not on module path")); @@ -1001,22 +990,6 @@ } } - enum Section { - NATIVE_LIBS("native"), - NATIVE_CMDS("bin"), - CLASSES("classes"), - CONFIG("conf"), - UNKNOWN("unknown"); - - private final String jmodDir; - - Section(String jmodDir) { - this.jmodDir = jmodDir; - } - - String jmodDir() { return jmodDir; } - } - static class ClassPathConverter implements ValueConverter { static final ValueConverter INSTANCE = new ClassPathConverter();