1 /* 2 * Copyright (c) 2014, 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.module; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.UncheckedIOException; 31 import java.nio.file.Files; 32 import java.nio.file.NoSuchFileException; 33 import java.nio.file.Path; 34 import java.nio.file.Paths; 35 import java.nio.file.attribute.BasicFileAttributes; 36 import java.util.HashSet; 37 import java.util.Set; 38 import java.util.stream.Collectors; 39 40 /** 41 * GenJdepsModulesXml augments the input modules.xml file(s) 42 * to include the module membership from the given path to 43 * the JDK exploded image. The output file is used by jdeps 44 * to analyze dependencies and enforce module boundaries. 45 * 46 * The input modules.xml file defines the modular structure of 47 * the JDK as described in JEP 200: The Modular JDK 48 * (http://openjdk.java.net/jeps/200). 49 * 50 * $ java build.tools.module.GenJdepsModulesXml \ 51 * -o com/sun/tools/jdeps/resources/modules.xml \ 52 * -mp $OUTPUTDIR/modules \ 53 * top/modules.xml 54 */ 55 public final class GenJdepsModulesXml { 56 private final static String USAGE = 57 "Usage: GenJdepsModulesXml -o <output file> -mp build/modules path-to-modules-xml"; 58 59 public static void main(String[] args) throws Exception { 60 Path outfile = null; 61 Path modulepath = null; 62 int i = 0; 63 while (i < args.length) { 64 String arg = args[i]; 65 if (arg.equals("-o")) { 66 outfile = Paths.get(args[i+1]); 67 i = i+2; 68 } else if (arg.equals("-mp")) { 69 modulepath = Paths.get(args[i+1]); 70 i = i+2; 71 if (!Files.isDirectory(modulepath)) { 72 System.err.println(modulepath + " is not a directory"); 73 System.exit(1); 74 } 75 } else { 76 break; 77 } 78 } 79 if (outfile == null || modulepath == null || i >= args.length) { 80 System.err.println(USAGE); 81 System.exit(-1); 82 } 83 84 GenJdepsModulesXml gentool = new GenJdepsModulesXml(modulepath); 85 Set<Module> modules = new HashSet<>(); 86 for (; i < args.length; i++) { 87 Path p = Paths.get(args[i]); 88 modules.addAll(ModulesXmlReader.readModules(p) 89 .stream() 90 .map(gentool::buildIncludes) 91 .collect(Collectors.toSet())); 92 } 93 94 Files.createDirectories(outfile.getParent()); 95 ModulesXmlWriter.writeModules(modules, outfile); 96 } 97 98 final Path modulepath; 99 public GenJdepsModulesXml(Path modulepath) { 100 this.modulepath = modulepath; 101 } 102 103 private static String packageName(Path p) { 104 return packageName(p.toString().replace(File.separatorChar, '/')); 105 } 106 private static String packageName(String name) { 107 int i = name.lastIndexOf('/'); 108 return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; 109 } 110 111 private static boolean includes(String name) { 112 return name.endsWith(".class"); 113 } 114 115 public Module buildIncludes(Module module) { 116 Module.Builder mb = new Module.Builder(module); 117 Path mclasses = modulepath.resolve(module.name()); 118 try { 119 Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr) 120 -> includes(p.getFileName().toString())) 121 .map(p -> packageName(mclasses.relativize(p))) 122 .forEach(mb::include); 123 } catch (NoSuchFileException e) { 124 // aggregate module may not have class 125 } catch (IOException ioe) { 126 throw new UncheckedIOException(ioe); 127 } 128 return mb.build(); 129 } 130 }