Module.java revision 3792:d516975e8110
137985Sphk/* 237985Sphk * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 337985Sphk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 437985Sphk * 537985Sphk * This code is free software; you can redistribute it and/or modify it 637985Sphk * under the terms of the GNU General Public License version 2 only, as 737985Sphk * published by the Free Software Foundation. Oracle designates this 837985Sphk * particular file as subject to the "Classpath" exception as provided 937985Sphk * by Oracle in the LICENSE file that accompanied this code. 1037985Sphk * 1137985Sphk * This code is distributed in the hope that it will be useful, but WITHOUT 1237985Sphk * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1337985Sphk * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1437985Sphk * version 2 for more details (a copy is included in the LICENSE file that 1537985Sphk * accompanied this code). 1637985Sphk * 1737985Sphk * You should have received a copy of the GNU General Public License version 1837985Sphk * 2 along with this work; if not, write to the Free Software Foundation, 1937985Sphk * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2037985Sphk * 2137985Sphk * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2237985Sphk * or visit www.oracle.com if you need additional information or have any 2337985Sphk * questions. 2437985Sphk */ 2537985Sphk 2637985Sphkpackage com.sun.tools.jdeps; 2737985Sphk 2850476Speterimport java.lang.module.ModuleDescriptor; 2948794Snikimport java.lang.module.ModuleDescriptor.Exports; 3037985Sphkimport java.lang.module.ModuleDescriptor.Opens; 3137985Sphkimport java.net.URI; 3279531Sruimport java.util.Collections; 3337985Sphkimport java.util.HashMap; 3437985Sphkimport java.util.HashSet; 3537985Sphkimport java.util.Map; 3659501Sphantomimport java.util.Set; 37124535Sru 3837985Sphk/** 3984306Sru * Jdeps internal representation of module for dependency analysis. 4037985Sphk */ 4137985Sphkclass Module extends Archive { 4237985Sphk static final Module UNNAMED_MODULE = new UnnamedModule(); 4337985Sphk static final String JDK_UNSUPPORTED = "jdk.unsupported"; 4437985Sphk 4537985Sphk static final boolean DEBUG = Boolean.getBoolean("jdeps.debug"); 4637985Sphk static void trace(String fmt, Object... args) { 4737985Sphk trace(DEBUG, fmt, args); 4837985Sphk } 4937985Sphk 5037985Sphk static void trace(boolean traceOn, String fmt, Object... args) { 5137985Sphk if (traceOn) { 5237985Sphk System.err.format(fmt, args); 53110442Scharnier } 5437985Sphk } 55110442Scharnier 5637985Sphk private final ModuleDescriptor descriptor; 5737985Sphk private final Map<String, Set<String>> exports; 5837985Sphk private final boolean isSystem; 5937985Sphk private final URI location; 6037985Sphk 6137985Sphk protected Module(String name) { 6237985Sphk super(name); 6338702Swosch this.descriptor = null; 6437985Sphk this.location = null; 6538702Swosch this.exports = Collections.emptyMap(); 6637985Sphk this.isSystem = true; 6738702Swosch } 6837985Sphk 69110442Scharnier private Module(String name, 7037985Sphk URI location, 71110442Scharnier ModuleDescriptor descriptor, 7273093Sru 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; 99 } 100 101 public ModuleDescriptor descriptor() { 102 return descriptor; 103 } 104 105 public URI location() { 106 return location; 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} 272