langtools/make/src/classes/build/tools/listjdkinternals/ListJDKInternals.java
changeset 45447 10df9eec1d04
parent 45415 41ab01cf1851
parent 45446 c79416fec66e
child 45448 4b53bf8b530c
equal deleted inserted replaced
45415:41ab01cf1851 45447:10df9eec1d04
     1 /*
       
     2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package build.tools.listjdkinternals;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.OutputStream;
       
    30 import java.io.PrintStream;
       
    31 import java.io.UncheckedIOException;
       
    32 import java.lang.module.ModuleDescriptor;
       
    33 import java.lang.module.ModuleFinder;
       
    34 import java.lang.module.ModuleReference;
       
    35 import java.net.URI;
       
    36 import java.nio.file.FileSystem;
       
    37 import java.nio.file.FileSystems;
       
    38 import java.nio.file.Files;
       
    39 import java.nio.file.Path;
       
    40 import java.nio.file.Paths;
       
    41 import java.nio.file.attribute.BasicFileAttributes;
       
    42 import java.time.LocalDateTime;
       
    43 import java.util.ArrayList;
       
    44 import java.util.Arrays;
       
    45 import java.util.HashMap;
       
    46 import java.util.HashSet;
       
    47 import java.util.List;
       
    48 import java.util.Map;
       
    49 import java.util.Set;
       
    50 import java.util.jar.JarEntry;
       
    51 import java.util.jar.JarFile;
       
    52 import java.util.stream.Collectors;
       
    53 
       
    54 /**
       
    55  * Run this tool to generate the JDK internal APIs in the previous releases
       
    56  * including platform-specific internal APIs.
       
    57  */
       
    58 public class ListJDKInternals {
       
    59     // Filter non-interesting JAR files
       
    60     private final static List<String> excludes = Arrays.asList(
       
    61         "deploy.jar",
       
    62         "javaws.jar",
       
    63         "plugin.jar",
       
    64         "cldrdata.jar",
       
    65         "localedata.jar"
       
    66     );
       
    67     private static void usage() {
       
    68         System.out.println("ListJDKInternals [-o <outfile>] <javaHome> [<javaHome>]*");
       
    69     }
       
    70 
       
    71     private static final Set<String> EXPORTED_PACKAGES = new HashSet<>();
       
    72 
       
    73     public static void main(String... args) throws IOException {
       
    74         List<Path> paths = new ArrayList<>();
       
    75         Path outFile = null;
       
    76         int i=0;
       
    77         while (i < args.length) {
       
    78             String arg = args[i++];
       
    79             if (arg.equals("-o")) {
       
    80                 outFile = Paths.get(args[i++]);
       
    81             } else {
       
    82                 Path p = Paths.get(arg);
       
    83                 if (Files.notExists(p))
       
    84                     throw new IllegalArgumentException(p + " not exist");
       
    85                 paths.add(p);
       
    86             }
       
    87         }
       
    88         if (paths.isEmpty()) {
       
    89             usage();
       
    90             System.exit(1);
       
    91         }
       
    92 
       
    93         // Get the exported APIs from the current JDK releases
       
    94         Path javaHome = Paths.get(System.getProperty("java.home"));
       
    95         ModuleFinder.ofSystem().findAll()
       
    96             .stream()
       
    97             .map(ModuleReference::descriptor)
       
    98             .filter(md -> !md.name().equals("jdk.unsupported"))
       
    99             .map(ModuleDescriptor::exports)
       
   100             .flatMap(Set::stream)
       
   101             .filter(exp -> !exp.isQualified())
       
   102             .map(ModuleDescriptor.Exports::source)
       
   103             .forEach(EXPORTED_PACKAGES::add);
       
   104 
       
   105         ListJDKInternals listJDKInternals = new ListJDKInternals(paths);
       
   106         if (outFile != null) {
       
   107             try (OutputStream out = Files.newOutputStream(outFile);
       
   108                  PrintStream pw = new PrintStream(out)) {
       
   109                 listJDKInternals.write(pw);
       
   110             }
       
   111         } else {
       
   112             listJDKInternals.write(System.out);
       
   113         }
       
   114     }
       
   115 
       
   116     private final Set<String> packages = new HashSet<>();
       
   117     ListJDKInternals(List<Path> dirs) throws IOException {
       
   118         for (Path p : dirs) {
       
   119             packages.addAll(list(p));
       
   120         }
       
   121     }
       
   122 
       
   123     private void write(PrintStream pw) {
       
   124         pw.println("# This file is auto-generated by ListJDKInternals tool on " +
       
   125                    LocalDateTime.now().toString());
       
   126         packages.stream().sorted()
       
   127                 .forEach(pw::println);
       
   128     }
       
   129 
       
   130     private Set<String> list(Path javaHome) throws IOException {
       
   131         Path jrt = javaHome.resolve("lib").resolve("modules");
       
   132         Path jre = javaHome.resolve("jre");
       
   133 
       
   134         if (Files.exists(jrt)) {
       
   135             return listModularRuntime(javaHome);
       
   136         } else if (Files.exists(jre.resolve("lib").resolve("rt.jar"))) {
       
   137             return listLegacyRuntime(javaHome);
       
   138         }
       
   139         throw new IllegalArgumentException("invalid " + javaHome);
       
   140     }
       
   141 
       
   142     private Set<String> listModularRuntime(Path javaHome) throws IOException {
       
   143         Map<String, String> env = new HashMap<>();
       
   144         env.put("java.home", javaHome.toString());
       
   145         FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env);
       
   146         Path root = fs.getPath("packages");
       
   147         return Files.walk(root, 1)
       
   148                     .map(Path::getFileName)
       
   149                     .map(Path::toString)
       
   150                     .filter(pn -> !EXPORTED_PACKAGES.contains(pn))
       
   151                     .collect(Collectors.toSet());
       
   152     }
       
   153 
       
   154     private Set<String> listLegacyRuntime(Path javaHome) throws IOException {
       
   155         List<Path> dirs = new ArrayList<>();
       
   156         Path jre = javaHome.resolve("jre");
       
   157         Path lib = javaHome.resolve("lib");
       
   158 
       
   159         dirs.add(jre.resolve("lib"));
       
   160         dirs.add(jre.resolve("lib").resolve("ext"));
       
   161         dirs.add(lib.resolve("tools.jar"));
       
   162         dirs.add(lib.resolve("jconsole.jar"));
       
   163         Set<String> packages = new HashSet<>();
       
   164         for (Path d : dirs) {
       
   165             Files.find(d, 1, (Path p, BasicFileAttributes attr)
       
   166                     -> p.getFileName().toString().endsWith(".jar") &&
       
   167                        !excludes.contains(p.getFileName().toString()))
       
   168                 .map(ListJDKInternals::walkJarFile)
       
   169                 .flatMap(Set::stream)
       
   170                 .filter(pn -> !EXPORTED_PACKAGES.contains(pn))
       
   171                 .forEach(packages::add);
       
   172         }
       
   173         return packages;
       
   174     }
       
   175 
       
   176     static Set<String> walkJarFile(Path jarfile) {
       
   177         try (JarFile jf = new JarFile(jarfile.toFile())) {
       
   178             return jf.stream()
       
   179                      .map(JarEntry::getName)
       
   180                      .filter(n -> n.endsWith(".class"))
       
   181                      .map(ListJDKInternals::toPackage)
       
   182                 .collect(Collectors.toSet());
       
   183         } catch (IOException e) {
       
   184             throw new UncheckedIOException(e);
       
   185         }
       
   186     }
       
   187 
       
   188     static String toPackage(String name) {
       
   189         int i = name.lastIndexOf('/');
       
   190         if (i < 0) {
       
   191             System.err.format("Warning: unnamed package %s%n", name);
       
   192         }
       
   193         return i >= 0 ? name.substring(0, i).replace("/", ".") : "";
       
   194     }
       
   195 }