/* * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package build.tools.listjdkinternals; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.UncheckedIOException; import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleFinder; import java.lang.module.ModuleReference; import java.net.URI; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.stream.Collectors; /** * Run this tool to generate the JDK internal APIs in the previous releases * including platform-specific internal APIs. */ public class ListJDKInternals { // Filter non-interesting JAR files private final static List<String> excludes = Arrays.asList( "deploy.jar", "javaws.jar", "plugin.jar", "cldrdata.jar", "localedata.jar" ); private static void usage() { System.out.println("ListJDKInternals [-o <outfile>] <javaHome> [<javaHome>]*"); } private static final Set<String> EXPORTED_PACKAGES = new HashSet<>(); public static void main(String... args) throws IOException { List<Path> paths = new ArrayList<>(); Path outFile = null; int i=0; while (i < args.length) { String arg = args[i++]; if (arg.equals("-o")) { outFile = Paths.get(args[i++]); } else { Path p = Paths.get(arg); if (Files.notExists(p)) throw new IllegalArgumentException(p + " not exist"); paths.add(p); } } if (paths.isEmpty()) { usage(); System.exit(1); } // Get the exported APIs from the current JDK releases Path javaHome = Paths.get(System.getProperty("java.home")); ModuleFinder.ofSystem().findAll() .stream() .map(ModuleReference::descriptor) .filter(md -> !md.name().equals("jdk.unsupported")) .map(ModuleDescriptor::exports) .flatMap(Set::stream) .filter(exp -> !exp.isQualified()) .map(ModuleDescriptor.Exports::source) .forEach(EXPORTED_PACKAGES::add); ListJDKInternals listJDKInternals = new ListJDKInternals(paths); if (outFile != null) { try (OutputStream out = Files.newOutputStream(outFile); PrintStream pw = new PrintStream(out)) { listJDKInternals.write(pw); } } else { listJDKInternals.write(System.out); } } private final Set<String> packages = new HashSet<>(); ListJDKInternals(List<Path> dirs) throws IOException { for (Path p : dirs) { packages.addAll(list(p)); } } private void write(PrintStream pw) { pw.println("# This file is auto-generated by ListJDKInternals tool on " + LocalDateTime.now().toString()); packages.stream().sorted() .forEach(pw::println); } private Set<String> list(Path javaHome) throws IOException { Path jrt = javaHome.resolve("lib").resolve("modules"); Path jre = javaHome.resolve("jre"); if (Files.exists(jrt)) { return listModularRuntime(javaHome); } else if (Files.exists(jre.resolve("lib").resolve("rt.jar"))) { return listLegacyRuntime(javaHome); } throw new IllegalArgumentException("invalid " + javaHome); } private Set<String> listModularRuntime(Path javaHome) throws IOException { Map<String, String> env = new HashMap<>(); env.put("java.home", javaHome.toString()); FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env); Path root = fs.getPath("packages"); return Files.walk(root, 1) .map(Path::getFileName) .map(Path::toString) .filter(pn -> !EXPORTED_PACKAGES.contains(pn)) .collect(Collectors.toSet()); } private Set<String> listLegacyRuntime(Path javaHome) throws IOException { List<Path> dirs = new ArrayList<>(); Path jre = javaHome.resolve("jre"); Path lib = javaHome.resolve("lib"); dirs.add(jre.resolve("lib")); dirs.add(jre.resolve("lib").resolve("ext")); dirs.add(lib.resolve("tools.jar")); dirs.add(lib.resolve("jconsole.jar")); Set<String> packages = new HashSet<>(); for (Path d : dirs) { Files.find(d, 1, (Path p, BasicFileAttributes attr) -> p.getFileName().toString().endsWith(".jar") && !excludes.contains(p.getFileName().toString())) .map(ListJDKInternals::walkJarFile) .flatMap(Set::stream) .filter(pn -> !EXPORTED_PACKAGES.contains(pn)) .forEach(packages::add); } return packages; } static Set<String> walkJarFile(Path jarfile) { try (JarFile jf = new JarFile(jarfile.toFile())) { return jf.stream() .map(JarEntry::getName) .filter(n -> n.endsWith(".class")) .map(ListJDKInternals::toPackage) .collect(Collectors.toSet()); } catch (IOException e) { throw new UncheckedIOException(e); } } static String toPackage(String name) { int i = name.lastIndexOf('/'); if (i < 0) { System.err.format("Warning: unnamed package %s%n", name); } return i >= 0 ? name.substring(0, i).replace("/", ".") : ""; } }