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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 import com.sun.tools.jdeps.DepsAnalyzer; 26 27 import java.util.Collections; 28 import java.util.LinkedHashMap; 29 import java.util.Map; 30 import java.util.Set; 31 32 import static com.sun.tools.jdeps.DepsAnalyzer.Info.*; 33 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; 34 import static java.lang.module.ModuleDescriptor.*; 35 36 import static org.testng.Assert.assertEquals; 37 import static org.testng.Assert.assertTrue; 38 39 40 public class ModuleMetaData { 41 public static final String JAVA_BASE = "java.base"; 42 43 static final String INTERNAL = "(internal)"; 44 static final String QUALIFIED = "(qualified)"; 45 static final String JDK_INTERNAL = "JDK internal API"; 46 static final String REMOVED_JDK_INTERNAL = "JDK removed internal API"; 47 48 final String moduleName; 49 final boolean isNamed; 50 final Map<String, ModuleRequires> requires = new LinkedHashMap<>(); 51 final Map<String, Dependence> references = new LinkedHashMap<>(); 52 final Map<String, Set<String>> exports = new LinkedHashMap<>(); 53 ModuleMetaData(String name)54 ModuleMetaData(String name) { 55 this(name, true); 56 } 57 ModuleMetaData(String name, boolean isNamed)58 ModuleMetaData(String name, boolean isNamed) { 59 this.moduleName = name; 60 this.isNamed = isNamed; 61 requires(JAVA_BASE); // implicit requires 62 } 63 name()64 String name() { 65 return moduleName; 66 } 67 requires(String name)68 ModuleMetaData requires(String name) { 69 requires.put(name, new ModuleRequires(name)); 70 return this; 71 } 72 requiresTransitive(String name)73 ModuleMetaData requiresTransitive(String name) { 74 requires.put(name, new ModuleRequires(name, TRANSITIVE)); 75 return this; 76 } 77 78 // for unnamed module depends(String name)79 ModuleMetaData depends(String name) { 80 requires.put(name, new ModuleRequires(name)); 81 return this; 82 } 83 reference(String origin, String target, String module)84 ModuleMetaData reference(String origin, String target, String module) { 85 return dependence(origin, target, module, ""); 86 } 87 internal(String origin, String target, String module)88 ModuleMetaData internal(String origin, String target, String module) { 89 return dependence(origin, target, module, INTERNAL); 90 } 91 qualified(String origin, String target, String module)92 ModuleMetaData qualified(String origin, String target, String module) { 93 return dependence(origin, target, module, QUALIFIED); 94 } 95 jdkInternal(String origin, String target, String module)96 ModuleMetaData jdkInternal(String origin, String target, String module) { 97 return dependence(origin, target, module, JDK_INTERNAL); 98 } removedJdkInternal(String origin, String target)99 ModuleMetaData removedJdkInternal(String origin, String target) { 100 return dependence(origin, target, REMOVED_JDK_INTERNAL, REMOVED_JDK_INTERNAL); 101 } 102 exports(String pn, Set<String> targets)103 ModuleMetaData exports(String pn, Set<String> targets) { 104 exports.put(pn, targets); 105 return this; 106 } 107 dependence(String origin, String target, String module, String access)108 private ModuleMetaData dependence(String origin, String target, String module, String access) { 109 references.put(key(origin, target), new Dependence(origin, target, module, access)); 110 return this; 111 } 112 key(String origin, String target)113 String key(String origin, String target) { 114 return origin + ":" + target; 115 } 116 checkRequires(String name, Set<DepsAnalyzer.Node> adjacentNodes)117 void checkRequires(String name, Set<DepsAnalyzer.Node> adjacentNodes) { 118 // System.err.format("%s: Expected %s Found %s %n", name, requires, adjacentNodes); 119 adjacentNodes.stream() 120 .forEach(v -> checkRequires(v.name)); 121 assertEquals(adjacentNodes.size(), requires.size()); 122 } 123 checkRequires(String name)124 void checkRequires(String name) { 125 ModuleRequires req = requires.get(name); 126 if (req == null) 127 System.err.println(moduleName + ": unexpected requires " + name); 128 assertTrue(requires.containsKey(name)); 129 } 130 checkRequires(Requires require)131 void checkRequires(Requires require) { 132 String name = require.name(); 133 if (name.equals(JAVA_BASE)) 134 return; 135 136 ModuleRequires req = requires.get(name); 137 if (req == null) 138 System.err.format("%s: unexpected dependence %s%n", moduleName, name); 139 140 assertTrue(requires.containsKey(name)); 141 142 assertEquals(require.modifiers(), req.modifiers()); 143 } 144 checkDependences(String name, Set<DepsAnalyzer.Node> adjacentNodes)145 void checkDependences(String name, Set<DepsAnalyzer.Node> adjacentNodes) { 146 // System.err.format("%s: Expected %s Found %s %n", name, references, adjacentNodes); 147 148 adjacentNodes.stream() 149 .forEach(v -> checkDependence(name, v.name, v.source, v.info)); 150 assertEquals(adjacentNodes.size(), references.size()); 151 } 152 checkDependence(String origin, String target, String module, DepsAnalyzer.Info info)153 void checkDependence(String origin, String target, String module, DepsAnalyzer.Info info) { 154 String key = key(origin, target); 155 Dependence dep = references.get(key); 156 String access = ""; 157 if (info == QUALIFIED_EXPORTED_API) 158 access = QUALIFIED; 159 else if (info == JDK_INTERNAL_API) 160 access = JDK_INTERNAL; 161 else if (info == JDK_REMOVED_INTERNAL_API) 162 access = REMOVED_JDK_INTERNAL; 163 else if (info == INTERNAL_API) 164 access = INTERNAL; 165 166 assertTrue(references.containsKey(key)); 167 168 assertEquals(dep.access, access); 169 assertEquals(dep.module, module); 170 } 171 172 173 public static class ModuleRequires { 174 final String name; 175 final Requires.Modifier mod; 176 ModuleRequires(String name)177 ModuleRequires(String name) { 178 this.name = name; 179 this.mod = null; 180 } 181 ModuleRequires(String name, Requires.Modifier mod)182 ModuleRequires(String name, Requires.Modifier mod) { 183 this.name = name; 184 this.mod = mod; 185 } 186 modifiers()187 Set<Requires.Modifier> modifiers() { 188 return mod != null ? Set.of(mod) : Collections.emptySet(); 189 } 190 191 @Override toString()192 public String toString() { 193 return name; 194 } 195 } 196 197 public static class Dependence { 198 final String origin; 199 final String target; 200 final String module; 201 final String access; 202 Dependence(String origin, String target, String module, String access)203 Dependence(String origin, String target, String module, String access) { 204 this.origin = origin; 205 this.target = target; 206 this.module = module; 207 this.access = access; 208 } 209 210 @Override toString()211 public String toString() { 212 return String.format("%s -> %s (%s) %s", origin, target, module, access); 213 } 214 } 215 } 216