blob: 89cbc2892aa1a4d54478a28274a38afda39c64ec [file] [log] [blame]
/*
* Copyright (c) 2016, 2017, 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.jigsaw;
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;
import java.util.stream.Stream;
/**
* Run this tool to generate the JDK internal APIs in the previous releases
* including platform-specific internal APIs.
*/
public class ListPackages {
// 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("ListPackages [-o <outfile>] [-jdkinternals] <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;
boolean jdkinternals = false;
int i=0;
while (i < args.length) {
String arg = args[i++];
if (arg.equals("-o")) {
outFile = Paths.get(args[i++]);
} else if (arg.equals("-jdkinternals")) {
jdkinternals = true;
} 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"))
.flatMap(md -> md.exports().stream())
.filter(exp -> !exp.isQualified())
.map(ModuleDescriptor.Exports::source)
.forEach(EXPORTED_PACKAGES::add);
ListPackages listPackages = new ListPackages(paths);
Stream<String> pkgs = listPackages.packages().stream();
if (jdkinternals) {
pkgs = pkgs.filter(pn -> !EXPORTED_PACKAGES.contains(pn));
}
if (outFile != null) {
try (OutputStream out = Files.newOutputStream(outFile);
PrintStream pw = new PrintStream(out)) {
write(pw, pkgs);
}
} else {
write(System.out, pkgs);
}
}
private static void write(PrintStream pw, Stream<String> packages) {
pw.println("# This file is auto-generated by ListPackages tool on " +
LocalDateTime.now().toString());
packages.sorted().forEach(pw::println);
}
private final Set<String> packages = new HashSet<>();
ListPackages(List<Path> dirs) throws IOException {
for (Path p : dirs) {
packages.addAll(list(p));
}
}
Set<String> packages() {
return packages;
}
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)
.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(ListPackages::walkJarFile)
.forEach(packages::addAll);
}
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(ListPackages::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("/", ".") : "";
}
}