1 /* 2 * Copyright (c) 2016, 2020, 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 package org.openjdk.asmtools.common; 24 25 import org.openjdk.asmtools.jdis.Indenter; 26 27 import java.util.*; 28 import java.util.stream.Collectors; 29 30 import static java.lang.String.format; 31 32 /** 33 * Internal presentation of a module 34 */ 35 public final class Module extends Indenter { 36 37 //* A module name and module_flags 38 public final Header header; 39 //* A service dependence's of this module 40 public final Set<Uses> uses; 41 //* Modules on which the current module has a dependence. 42 public final Set<Dependence> requires; 43 //* A module exports, may be qualified or unqualified. 44 public final Map<Exported, Set<String>> exports; 45 //* Packages, to be opened by the current module 46 public final Map<Opened, Set<String>> opens; 47 //* A service that a module provides one or more implementations of. 48 public final Map<Provided, Set<String>> provides; 49 50 private Module(Builder builder) { 51 this.header = builder.header; 52 this.requires = Collections.unmodifiableSet(builder.requires); 53 this.exports = Collections.unmodifiableMap(builder.exports); 54 this.opens = Collections.unmodifiableMap(builder.opens); 55 this.uses = Collections.unmodifiableSet(builder.uses); 56 this.provides = Collections.unmodifiableMap(builder.provides); 57 } 58 59 public String getModuleFlags () { 60 return Modifier.getModuleModifiers(header.getFlags()); 61 } 62 public String getModuleName () { return header.getModuleName(); } 63 public String getModuleVersion() { return header.getModuleVersion(); }; 64 65 @Override 66 public String toString() { 67 StringBuilder sb = new StringBuilder(); 68 int l = 0; 69 requires.stream() 70 .sorted() 71 .forEach(d -> sb.append(getIndentString()).append(format("requires %s;%s%n", 72 d.toString(), 73 d.getModuleVersion() == null ? "" : " // @" + d.getModuleVersion()))); 74 // 75 l = newLine(sb,l); 76 exports.entrySet().stream() 77 .filter(e -> e.getValue().isEmpty()) 78 .sorted(Map.Entry.comparingByKey()) 79 .map(e -> format("%sexports %s;%n", getIndentString(), e.getKey().toString())) 80 .forEach(sb::append); 81 exports.entrySet().stream() 82 .filter(e -> !e.getValue().isEmpty()) 83 .sorted(Map.Entry.comparingByKey()) 84 .map(e -> format("%sexports %s to%n%s;%n", getIndentString(), e.getKey().toString(), 85 e.getValue().stream().sorted() 86 .map(mn -> format("%s %s", getIndentString(), mn)) 87 .collect(Collectors.joining(",\n")))) 88 .forEach(sb::append); 89 // 90 l = newLine(sb,l); 91 opens.entrySet().stream() 92 .filter(e -> e.getValue().isEmpty()) 93 .sorted(Map.Entry.comparingByKey()) 94 .map(e -> format("%sopens %s;%n", getIndentString(), e.getKey().toString())) 95 .forEach(sb::append); 96 opens.entrySet().stream() 97 .filter(e -> !e.getValue().isEmpty()) 98 .sorted(Map.Entry.comparingByKey()) 99 .map(e -> format("%sopens %s to%n%s;%n", getIndentString(), e.getKey().toString(), 100 e.getValue().stream().sorted() 101 .map(mn -> format("%s %s", getIndentString(), mn)) 102 .collect(Collectors.joining(",\n")))) 103 .forEach(sb::append); 104 // 105 l = newLine(sb,l); 106 uses.stream().sorted() 107 .map(s -> format("%suses %s;%n", getIndentString(), s)) 108 .forEach(sb::append); 109 // 110 l = newLine(sb,l); 111 provides.entrySet().stream() 112 .filter(e -> !e.getValue().isEmpty()) 113 .sorted(Map.Entry.comparingByKey()) 114 .map(e -> format("%sprovides %s with%n%s;%n", getIndentString(), e.getKey().toString(), 115 e.getValue().stream().sorted() 116 .map(mn -> format("%s %s", getIndentString(), mn)) 117 .collect(Collectors.joining(",\n")))) 118 .forEach(sb::append); 119 // 120 if( Character.isWhitespace(sb.charAt(sb.length()-1)) ) 121 sb.deleteCharAt(sb.length()-1); 122 return sb.toString(); 123 } 124 125 private int newLine(StringBuilder sb, int length) { 126 if(sb.length() > length) { 127 sb.append("\n"); 128 return sb.length() + 1; 129 } 130 return length; 131 } 132 133 /** 134 * Modules flags 135 */ 136 public enum Modifier { 137 ACC_NONE(0x0000, "", ""), 138 ACC_OPEN(0x0020, "open", "ACC_OPEN"), 139 ACC_TRANSITIVE(0x0020, "transitive", "ACC_TRANSITIVE"), 140 ACC_STATIC_PHASE(0x0040, "static", "ACC_STATIC_PHASE"), 141 ACC_SYNTHETIC(0x1000, "", "ACC_SYNTHETIC"), 142 ACC_MANDATED(0x8000, "", "ACC_MANDATED"); 143 private final int value; 144 private final String keyword; 145 private final String flag; 146 Modifier(int value, String keyword, String flagName) { 147 this.value = value; 148 this.keyword = keyword; 149 this.flag = flagName; 150 } 151 152 public int asInt() { return value; } 153 154 public static String getModuleModifiers(int flag) { 155 return asString(flag, false, ACC_TRANSITIVE); 156 } 157 158 public static String getModuleFlags(int flag) { 159 return asString(flag, true, ACC_TRANSITIVE); 160 } 161 162 public static String getStatementModifiers(int flag) { 163 return asString(flag, false, ACC_OPEN); 164 } 165 166 public static String getStatementFlags(int flag) { 167 return asString(flag, true, ACC_OPEN); 168 } 169 170 private static String asString(int value, boolean flagFormat, Modifier skipped ) { 171 String buf = ""; 172 for(Module.Modifier m : values()) { 173 if( m != skipped && (value & m.value) != 0) { 174 buf += ((flagFormat) ? m.flag : m.keyword) + " "; 175 value ^= m.value; 176 } 177 } 178 if( flagFormat && value != 0 ) 179 buf += String.format("0x%04X ", value); 180 return buf; 181 } 182 } 183 184 // A module header consists of a module name and module flags 185 public final static class Header extends VersionedFlaggedTargetType{ 186 Header(String typeName, int flag) { this(typeName, flag, null); } 187 Header(String typeName, int flag, String moduleVersion) { super(typeName, flag, moduleVersion); } 188 public String getModuleName() { return getTypeName(); } 189 public int getModuleFlags() { return getFlags(); } 190 public String getModuleVersion() { return getVersion(); } 191 } 192 193 //* A module on which the current module has a dependence. 194 public final static class Dependence extends VersionedFlaggedTargetType { 195 public Dependence(String moduleName, int flag) {this(moduleName, flag, null);} 196 public Dependence(String moduleName, int flag, String moduleVersion) {super(moduleName, flag, moduleVersion);} 197 public Dependence(String moduleName, boolean transitive, boolean staticPhase) { this(moduleName,transitive,staticPhase,null);} 198 public Dependence(String moduleName, boolean transitive, boolean staticPhase, String moduleVersion) { 199 this(moduleName, 200 (transitive ? Modifier.ACC_TRANSITIVE.value : Modifier.ACC_NONE.value) | 201 (staticPhase ? Modifier.ACC_STATIC_PHASE.value : Modifier.ACC_NONE.value), moduleVersion); 202 } 203 public String getModuleVersion() { return getVersion(); } 204 } 205 206 public final static class Uses extends TargetType { 207 public Uses(String typeName) { super(typeName); } 208 } 209 210 //* A provided type of the current module. 211 public final static class Provided extends TargetType { 212 public Provided(String typeName) { super(typeName); } 213 } 214 215 //* An opened package of the current module. 216 public final static class Opened extends FlaggedTargetType { 217 public Opened(String typeName) { 218 super(typeName, 0); 219 } 220 public Opened(String typeName, int opensFlags) { 221 super(typeName, opensFlags); 222 } 223 } 224 225 //* An exported package of the current module. 226 public final static class Exported extends FlaggedTargetType { 227 public Exported(String typeName) { 228 super(typeName, 0); 229 } 230 231 public Exported(String typeName, int exportsFlags) { 232 super(typeName, exportsFlags); 233 } 234 } 235 236 public static class VersionedFlaggedTargetType extends FlaggedTargetType { 237 private String version; 238 239 VersionedFlaggedTargetType(String typeName, int flag) { 240 this(typeName,flag, null); 241 } 242 243 VersionedFlaggedTargetType(String typeName, int flag, String version) { 244 super(typeName, flag); 245 this.version = version != null && !version.isEmpty() ? version : null; 246 } 247 public String getVersion() { return version; } 248 249 @Override 250 public int hashCode() { 251 int code = version == null ? 0 : version.hashCode(); 252 return code + super.hashCode(); 253 } 254 } 255 256 public static class FlaggedTargetType extends TargetType { 257 private int flag; 258 259 FlaggedTargetType(String typeName, int flag) { 260 super(typeName); 261 this.flag = flag; 262 } 263 264 public boolean isFlagged() { 265 return true; 266 } 267 268 public int getFlags() { 269 return flag; 270 } 271 272 public void setFlag(int value) { flag = value; } 273 274 @Override 275 public int hashCode() { 276 return super.hashCode() + flag; 277 } 278 279 @Override 280 public boolean equals(Object o) { 281 return super.equals(o) && ((FlaggedTargetType) o).flag == this.flag; 282 } 283 284 @Override 285 public String toString() { 286 return Modifier.getStatementModifiers(this.flag)+ super.toString(); 287 } 288 } 289 290 public static class TargetType implements Comparable<TargetType> { 291 private String typeName; 292 293 TargetType(String typeName) { this.typeName = typeName; } 294 295 public String getTypeName() { 296 return typeName; 297 } 298 299 public void setTypeName(String value) { typeName = value; } 300 301 public boolean isFlagged() { 302 return false; 303 } 304 305 @Override 306 public int hashCode() { return typeName.hashCode() * 11; } 307 308 @Override 309 public boolean equals(Object o) { 310 if (o instanceof TargetType) { 311 TargetType t = (TargetType) o; 312 return this.typeName.equals(t.getTypeName()); 313 } 314 return false; 315 } 316 317 @Override 318 public int compareTo(TargetType t) { 319 return this.typeName.compareTo(t.getTypeName()); 320 } 321 322 @Override 323 public String toString() { 324 return typeName; 325 } 326 } 327 328 /** 329 * The module builder. 330 */ 331 public static final class Builder { 332 final Header header; 333 final Set<Dependence> requires = new HashSet<>(); 334 final Map<Exported, Set<String>> exports = new HashMap<>(); 335 final Map<Opened, Set<String>> opens = new HashMap<>(); 336 final Set<Uses> uses = new HashSet<>(); 337 final Map<Provided, Set<String>> provides = new HashMap<>(); 338 339 340 public Builder() { 341 this("", Modifier.ACC_NONE.asInt(), null); 342 } 343 344 public Builder(String moduleName, int moduleFlags, String moduleVersion) { 345 header = new Header( moduleName,moduleFlags, moduleVersion); 346 } 347 348 public Builder setModuleFlags(int moduleFlags) { 349 header.setFlag(header.getFlags() | moduleFlags); 350 return this; 351 } 352 353 public Builder setModuleFlags(Modifier... moduleFlags) { 354 for (Modifier m : moduleFlags) 355 setModuleFlags(m.value); 356 return this; 357 } 358 359 public Builder setModuleName(String value) { 360 header.setTypeName(value); 361 return this; 362 } 363 364 public Builder require(String d, boolean transitive, boolean staticPhase, String version) { 365 requires.add(new Dependence(d, transitive, staticPhase, version)); 366 return this; 367 } 368 369 public Builder require(String d, int requiresFlag, String version) { 370 requires.add(new Dependence(d, requiresFlag, version)); 371 return this; 372 } 373 374 public Builder require(String d, int requiresFlag) { 375 requires.add(new Dependence(d, requiresFlag, null)); 376 return this; 377 } 378 379 public Builder opens(Opened p, Set<String> ms) { 380 return add(opens, p, ms); 381 } 382 383 public Builder opens(String packageName, int exportFlags, Set<String> ms) { 384 return add(opens, new Opened(packageName, exportFlags), ms); 385 } 386 387 public Builder opens(String packageName, int exportFlags) { 388 return add(opens, new Opened(packageName, exportFlags), new HashSet<>()); 389 } 390 391 392 public Builder exports(Exported p, Set<String> ms) { 393 return add(exports, p, ms); 394 } 395 396 public Builder exports(String packageName, int exportFlags, Set<String> ms) { 397 return add(exports, new Exported(packageName, exportFlags), ms); 398 } 399 400 public Builder exports(String packageName, int exportFlags) { 401 return add(exports, new Exported(packageName, exportFlags), new HashSet<>()); 402 } 403 404 public Builder uses(String serviceName) { 405 uses.add(new Uses(serviceName)); 406 return this; 407 } 408 409 410 public Builder uses(Set<String> serviceNames) { 411 uses.addAll(serviceNames.stream().map(Uses::new).collect(Collectors.toList())); 412 return this; 413 } 414 415 public Builder provides(Provided t, Set<String> implementations) { 416 return add(provides, t, implementations); 417 } 418 419 public Builder provides(String serviceName, Set<String> implementations) { 420 return add(provides, new Provided(serviceName), implementations); 421 } 422 423 424 /** 425 * @return The new module 426 */ 427 public Module build() { 428 return new Module(this); 429 } 430 431 private <T extends TargetType> Builder add( Map<T, Set<String>> collection, T source, Set<String> target) { 432 Objects.requireNonNull(source); 433 Objects.requireNonNull(target); 434 if (!collection.containsKey(source)) 435 collection.put(source, new HashSet<>()); 436 collection.get(source).addAll(target); 437 return this; 438 } 439 } 440 }