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 com.sun.tools.jdeps; 27 28 import java.lang.module.ModuleDescriptor; 29 import java.lang.module.ModuleDescriptor.Exports; 30 import java.lang.module.ModuleDescriptor.Opens; 31 import java.net.URI; 32 import java.util.Collections; 33 import java.util.HashMap; 34 import java.util.HashSet; 35 import java.util.Map; 36 import java.util.Set; 37 38 /** 39 * Jdeps internal representation of module for dependency analysis. 40 */ 41 class Module extends Archive { 42 static final Module UNNAMED_MODULE = new UnnamedModule(); 43 static final String JDK_UNSUPPORTED = "jdk.unsupported"; 44 45 static final boolean DEBUG = Boolean.getBoolean("jdeps.debug"); 46 static void trace(String fmt, Object... args) { 47 trace(DEBUG, fmt, args); 48 } 49 50 static void trace(boolean traceOn, String fmt, Object... args) { 51 if (traceOn) { 52 System.err.format(fmt, args); 53 } 54 } 55 56 private final ModuleDescriptor descriptor; 57 private final Map<String, Set<String>> exports; 58 private final boolean isSystem; 59 private final URI location; 60 61 protected Module(String name) { 62 super(name); 63 this.descriptor = null; 64 this.location = null; 65 this.exports = Collections.emptyMap(); 66 this.isSystem = true; 67 } 68 69 private Module(String name, 70 URI location, 71 ModuleDescriptor descriptor, 72 Map<String, Set<String>> exports, 73 boolean isSystem, 74 ClassFileReader reader) { 75 super(name, location, reader); 76 this.descriptor = descriptor; 77 this.location = location; 78 this.exports = Collections.unmodifiableMap(exports); 79 this.isSystem = isSystem; 80 } 81 82 /** 83 * Returns module name 84 */ 85 public String name() { 86 return descriptor != null ? descriptor.name() : getName(); 87 } 88 89 public boolean isNamed() { 90 return true; 91 } 92 93 public boolean isAutomatic() { 94 return descriptor.isAutomatic(); 95 } 96 97 public Module getModule() { 98 return this; 107 } 108 109 public boolean isJDK() { 110 String mn = name(); 111 return isSystem && 112 (mn.startsWith("java.") || mn.startsWith("jdk.") || mn.startsWith("javafx.")); 113 } 114 115 public boolean isSystem() { 116 return isSystem; 117 } 118 119 public Map<String, Set<String>> exports() { 120 return exports; 121 } 122 123 public Set<String> packages() { 124 return descriptor.packages(); 125 } 126 127 /** 128 * Tests if the package of the given name is exported. 129 */ 130 public boolean isExported(String pn) { 131 return exports.containsKey(pn) ? exports.get(pn).isEmpty() : false; 132 } 133 134 public boolean isJDKUnsupported() { 135 return JDK_UNSUPPORTED.equals(this.name()); 136 } 137 138 /** 139 * Converts this module to a strict module with the given dependences 140 * 141 * @throws IllegalArgumentException if this module is not an automatic module 142 */ 143 public Module toStrictModule(Map<String, Boolean> requires) { 144 if (!isAutomatic()) { 145 throw new IllegalArgumentException(name() + " already a strict module"); 146 } 147 return new StrictModule(this, requires); 148 } 149 150 /** 151 * Tests if the package of the given name is qualifiedly exported 152 * to the target. 153 */ 154 public boolean isExported(String pn, String target) { 155 return isExported(pn) || exports.containsKey(pn) && exports.get(pn).contains(target); 156 } 157 158 @Override 159 public String toString() { 160 return name(); 161 } 162 163 public final static class Builder { 164 final String name; 165 final ModuleDescriptor descriptor; 166 final boolean isSystem; 167 ClassFileReader reader; 168 URI location; 169 170 public Builder(ModuleDescriptor md) { 171 this(md, false); 172 } 173 174 public Builder(ModuleDescriptor md, boolean isSystem) { 175 this.name = md.name(); 176 this.descriptor = md; 177 this.isSystem = isSystem; 178 } 179 180 public Builder location(URI location) { 181 this.location = location; 182 return this; 183 } 184 185 public Builder classes(ClassFileReader reader) { 186 this.reader = reader; 187 return this; 188 } 189 190 public Module build() { 191 if (descriptor.isAutomatic() && isSystem) { 192 throw new InternalError("JDK module: " + name + " can't be automatic module"); 193 } 194 195 Map<String, Set<String>> exports = new HashMap<>(); 196 197 descriptor.exports().stream() 198 .forEach(exp -> exports.computeIfAbsent(exp.source(), _k -> new HashSet<>()) 199 .addAll(exp.targets())); 200 201 return new Module(name, location, descriptor, exports, isSystem, reader); 202 } 203 } 204 205 private static class UnnamedModule extends Module { 206 private UnnamedModule() { 207 super("unnamed", null, null, 208 Collections.emptyMap(), 209 false, null); 210 } 211 212 @Override 213 public String name() { 214 return "unnamed"; 215 } 216 217 @Override 218 public boolean isNamed() { 219 return false; 220 } 221 222 @Override 223 public boolean isAutomatic() { 224 return false; 225 } 226 227 @Override 228 public boolean isExported(String pn) { 229 return true; 230 } 231 } 232 233 private static class StrictModule extends Module { 234 private final ModuleDescriptor md; 235 236 /** 237 * Converts the given automatic module to a strict module. 238 * 239 * Replace this module's dependences with the given requires and also 240 * declare service providers, if specified in META-INF/services configuration file 241 */ 242 private StrictModule(Module m, Map<String, Boolean> requires) { 243 super(m.name(), m.location, m.descriptor, m.exports, m.isSystem, m.reader()); 244 245 ModuleDescriptor.Builder builder = ModuleDescriptor.module(m.name()); 246 requires.keySet().forEach(mn -> { 247 if (requires.get(mn).equals(Boolean.TRUE)) { 248 builder.requires(Set.of(ModuleDescriptor.Requires.Modifier.TRANSITIVE), mn); 249 } else { 250 builder.requires(mn); 251 } 252 }); 253 m.descriptor.exports().forEach(e -> builder.exports(e)); 254 m.descriptor.opens().forEach(o -> builder.opens(o)); 255 m.descriptor.uses().forEach(s -> builder.uses(s)); 256 m.descriptor.provides().forEach(p -> builder.provides(p)); 257 258 Set<String> concealed = new HashSet<>(m.descriptor.packages()); 259 m.descriptor.exports().stream().map(Exports::source).forEach(concealed::remove); 260 m.descriptor.opens().stream().map(Opens::source).forEach(concealed::remove); 261 concealed.forEach(builder::contains); 262 263 this.md = builder.build(); 264 } 265 266 @Override 267 public ModuleDescriptor descriptor() { 268 return md; 269 } 270 } 271 } | 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 com.sun.tools.jdeps; 27 28 import java.lang.module.ModuleDescriptor; 29 import java.net.URI; 30 import java.util.Collections; 31 import java.util.HashMap; 32 import java.util.HashSet; 33 import java.util.Map; 34 import java.util.Set; 35 36 /** 37 * Jdeps internal representation of module for dependency analysis. 38 */ 39 class Module extends Archive { 40 static final Module UNNAMED_MODULE = new UnnamedModule(); 41 static final String JDK_UNSUPPORTED = "jdk.unsupported"; 42 43 static final boolean DEBUG = Boolean.getBoolean("jdeps.debug"); 44 static void trace(String fmt, Object... args) { 45 trace(DEBUG, fmt, args); 46 } 47 48 static void trace(boolean traceOn, String fmt, Object... args) { 49 if (traceOn) { 50 System.err.format(fmt, args); 51 } 52 } 53 54 private final ModuleDescriptor descriptor; 55 private final Map<String, Set<String>> exports; 56 private final Map<String, Set<String>> opens; 57 private final boolean isSystem; 58 private final URI location; 59 60 protected Module(String name) { 61 super(name); 62 this.descriptor = null; 63 this.location = null; 64 this.exports = Collections.emptyMap(); 65 this.opens = Collections.emptyMap(); 66 this.isSystem = true; 67 } 68 69 private Module(String name, 70 URI location, 71 ModuleDescriptor descriptor, 72 Map<String, Set<String>> exports, 73 Map<String, Set<String>> opens, 74 boolean isSystem, 75 ClassFileReader reader) { 76 super(name, location, reader); 77 this.descriptor = descriptor; 78 this.location = location; 79 this.exports = Collections.unmodifiableMap(exports); 80 this.opens = Collections.unmodifiableMap(opens); 81 this.isSystem = isSystem; 82 } 83 84 /** 85 * Returns module name 86 */ 87 public String name() { 88 return descriptor != null ? descriptor.name() : getName(); 89 } 90 91 public boolean isNamed() { 92 return true; 93 } 94 95 public boolean isAutomatic() { 96 return descriptor.isAutomatic(); 97 } 98 99 public Module getModule() { 100 return this; 109 } 110 111 public boolean isJDK() { 112 String mn = name(); 113 return isSystem && 114 (mn.startsWith("java.") || mn.startsWith("jdk.") || mn.startsWith("javafx.")); 115 } 116 117 public boolean isSystem() { 118 return isSystem; 119 } 120 121 public Map<String, Set<String>> exports() { 122 return exports; 123 } 124 125 public Set<String> packages() { 126 return descriptor.packages(); 127 } 128 129 public boolean isJDKUnsupported() { 130 return JDK_UNSUPPORTED.equals(this.name()); 131 } 132 133 /** 134 * Converts this module to a normal module with the given dependences 135 * 136 * @throws IllegalArgumentException if this module is not an automatic module 137 */ 138 public Module toNormalModule(Map<String, Boolean> requires) { 139 if (!isAutomatic()) { 140 throw new IllegalArgumentException(name() + " not an automatic module"); 141 } 142 return new NormalModule(this, requires); 143 } 144 145 /** 146 * Tests if the package of the given name is exported. 147 */ 148 public boolean isExported(String pn) { 149 return exports.containsKey(pn) && exports.get(pn).isEmpty(); 150 } 151 152 /** 153 * Tests if the package of the given name is exported to the target 154 * in a qualified fashion. 155 */ 156 public boolean isExported(String pn, String target) { 157 return isExported(pn) 158 || exports.containsKey(pn) && exports.get(pn).contains(target); 159 } 160 161 /** 162 * Tests if the package of the given name is open. 163 */ 164 public boolean isOpen(String pn) { 165 return opens.containsKey(pn) && opens.get(pn).isEmpty(); 166 } 167 168 /** 169 * Tests if the package of the given name is open to the target 170 * in a qualified fashion. 171 */ 172 public boolean isOpen(String pn, String target) { 173 return isOpen(pn) 174 || opens.containsKey(pn) && opens.get(pn).contains(target); 175 } 176 177 @Override 178 public String toString() { 179 return name(); 180 } 181 182 public final static class Builder { 183 final String name; 184 final ModuleDescriptor descriptor; 185 final boolean isSystem; 186 ClassFileReader reader; 187 URI location; 188 189 public Builder(ModuleDescriptor md) { 190 this(md, false); 191 } 192 193 public Builder(ModuleDescriptor md, boolean isSystem) { 194 this.name = md.name(); 195 this.descriptor = md; 196 this.isSystem = isSystem; 197 } 198 199 public Builder location(URI location) { 200 this.location = location; 201 return this; 202 } 203 204 public Builder classes(ClassFileReader reader) { 205 this.reader = reader; 206 return this; 207 } 208 209 public Module build() { 210 if (descriptor.isAutomatic() && isSystem) { 211 throw new InternalError("JDK module: " + name + " can't be automatic module"); 212 } 213 214 Map<String, Set<String>> exports = new HashMap<>(); 215 Map<String, Set<String>> opens = new HashMap<>(); 216 217 if (descriptor.isAutomatic()) { 218 // ModuleDescriptor::exports and opens returns an empty set 219 descriptor.packages().forEach(pn -> exports.put(pn, Collections.emptySet())); 220 descriptor.packages().forEach(pn -> opens.put(pn, Collections.emptySet())); 221 } else { 222 descriptor.exports().stream() 223 .forEach(exp -> exports.computeIfAbsent(exp.source(), _k -> new HashSet<>()) 224 .addAll(exp.targets())); 225 descriptor.opens().stream() 226 .forEach(exp -> opens.computeIfAbsent(exp.source(), _k -> new HashSet<>()) 227 .addAll(exp.targets())); 228 } 229 return new Module(name, location, descriptor, exports, opens, isSystem, reader); 230 } 231 } 232 233 private static class UnnamedModule extends Module { 234 private UnnamedModule() { 235 super("unnamed", null, null, 236 Collections.emptyMap(), Collections.emptyMap(), 237 false, null); 238 } 239 240 @Override 241 public String name() { 242 return "unnamed"; 243 } 244 245 @Override 246 public boolean isNamed() { 247 return false; 248 } 249 250 @Override 251 public boolean isAutomatic() { 252 return false; 253 } 254 255 @Override 256 public boolean isExported(String pn) { 257 return true; 258 } 259 } 260 261 /** 262 * A normal module has a module-info.class 263 */ 264 private static class NormalModule extends Module { 265 private final ModuleDescriptor md; 266 267 /** 268 * Converts the given automatic module to a normal module. 269 * 270 * Replace this module's dependences with the given requires and also 271 * declare service providers, if specified in META-INF/services configuration file 272 */ 273 private NormalModule(Module m, Map<String, Boolean> requires) { 274 super(m.name(), m.location, m.descriptor, m.exports, m.opens, m.isSystem, m.reader()); 275 276 ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(m.name()); 277 requires.keySet().forEach(mn -> { 278 if (requires.get(mn).equals(Boolean.TRUE)) { 279 builder.requires(Set.of(ModuleDescriptor.Requires.Modifier.TRANSITIVE), mn); 280 } else { 281 builder.requires(mn); 282 } 283 }); 284 m.descriptor.packages().forEach(builder::exports); 285 m.descriptor.packages().forEach(builder::opens); 286 m.descriptor.uses().forEach(builder::uses); 287 m.descriptor.provides().forEach(builder::provides); 288 this.md = builder.build(); 289 } 290 291 @Override 292 public ModuleDescriptor descriptor() { 293 return md; 294 } 295 } 296 } |