jdk/make/src/classes/build/tools/module/Module.java
changeset 37294 eda408d4f253
parent 37292 64f6ae06310e
parent 36848 33688f44fb2a
child 37295 e00dfcc21fa1
equal deleted inserted replaced
37292:64f6ae06310e 37294:eda408d4f253
     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.util.Collections;
       
    29 import java.util.HashMap;
       
    30 import java.util.HashSet;
       
    31 import java.util.Map;
       
    32 import java.util.Objects;
       
    33 import java.util.Set;
       
    34 import java.util.stream.Collectors;
       
    35 import java.util.stream.Stream;
       
    36 
       
    37 public class Module {
       
    38     public static class Dependence implements Comparable<Dependence> {
       
    39         final String name;
       
    40         final boolean reexport;
       
    41         Dependence(String name) {
       
    42             this(name, false);
       
    43         }
       
    44         Dependence(String name, boolean reexport) {
       
    45             this.name = name;
       
    46             this.reexport = reexport;
       
    47         }
       
    48 
       
    49         public String name() {
       
    50             return name;
       
    51         }
       
    52 
       
    53         public boolean reexport(){
       
    54             return reexport;
       
    55         }
       
    56 
       
    57         @Override
       
    58         public int hashCode() {
       
    59             int hash = 5;
       
    60             hash = 11 * hash + Objects.hashCode(this.name);
       
    61             hash = 11 * hash + (this.reexport ? 1 : 0);
       
    62             return hash;
       
    63         }
       
    64 
       
    65         public boolean equals(Object o) {
       
    66             Dependence d = (Dependence)o;
       
    67             return this.name.equals(d.name) && this.reexport == d.reexport;
       
    68         }
       
    69 
       
    70         @Override
       
    71         public int compareTo(Dependence o) {
       
    72             int rc = this.name.compareTo(o.name);
       
    73             return rc != 0 ? rc : Boolean.compare(this.reexport, o.reexport);
       
    74         }
       
    75 
       
    76         @Override
       
    77         public String toString() {
       
    78             return String.format("requires %s%s;",
       
    79                                  reexport ? "public " : "", name);
       
    80         }
       
    81     }
       
    82     private final String moduleName;
       
    83     private final Set<Dependence> requires;
       
    84     private final Map<String, Set<String>> exports;
       
    85     private final Set<String> uses;
       
    86     private final Map<String, Set<String>> provides;
       
    87 
       
    88     private Module(String name,
       
    89                    Set<Dependence> requires,
       
    90                    Map<String, Set<String>> exports,
       
    91                    Set<String> uses,
       
    92                    Map<String, Set<String>> provides) {
       
    93         this.moduleName = name;
       
    94         this.requires = Collections.unmodifiableSet(requires);
       
    95         this.exports = Collections.unmodifiableMap(exports);
       
    96         this.uses  = Collections.unmodifiableSet(uses);
       
    97         this.provides = Collections.unmodifiableMap(provides);
       
    98     }
       
    99 
       
   100     public String name() {
       
   101         return moduleName;
       
   102     }
       
   103 
       
   104     public Set<Dependence> requires() {
       
   105         return requires;
       
   106     }
       
   107 
       
   108     public Map<String, Set<String>> exports() {
       
   109         return exports;
       
   110     }
       
   111 
       
   112     public Set<String> uses() {
       
   113         return uses;
       
   114     }
       
   115 
       
   116     public Map<String, Set<String>> provides() {
       
   117         return provides;
       
   118     }
       
   119 
       
   120     @Override
       
   121     public boolean equals(Object ob) {
       
   122         if (!(ob instanceof Module)) {
       
   123             return false;
       
   124         }
       
   125         Module that = (Module) ob;
       
   126         return (moduleName.equals(that.moduleName)
       
   127                 && requires.equals(that.requires)
       
   128                 && exports.equals(that.exports));
       
   129     }
       
   130 
       
   131     @Override
       
   132     public int hashCode() {
       
   133         int hc = moduleName.hashCode();
       
   134         hc = hc * 43 + requires.hashCode();
       
   135         hc = hc * 43 + exports.hashCode();
       
   136         return hc;
       
   137     }
       
   138 
       
   139     @Override
       
   140     public String toString() {
       
   141         StringBuilder sb = new StringBuilder();
       
   142         sb.append(String.format("module %s {%n", moduleName));
       
   143         requires.stream()
       
   144                 .sorted()
       
   145                 .map(d -> String.format("    requires %s%s;%n", d.reexport ? "public " : "", d.name))
       
   146                 .forEach(sb::append);
       
   147         exports.entrySet().stream()
       
   148                 .filter(e -> e.getValue().isEmpty())
       
   149                 .sorted(Map.Entry.comparingByKey())
       
   150                 .map(e -> String.format("    exports %s;%n", e.getKey()))
       
   151                 .forEach(sb::append);
       
   152         exports.entrySet().stream()
       
   153                 .filter(e -> !e.getValue().isEmpty())
       
   154                 .sorted(Map.Entry.comparingByKey())
       
   155                 .map(e -> String.format("    exports %s to%n%s;%n", e.getKey(),
       
   156                         e.getValue().stream().sorted()
       
   157                                 .map(mn -> String.format("        %s", mn))
       
   158                                 .collect(Collectors.joining(",\n"))))
       
   159                 .forEach(sb::append);
       
   160         uses.stream().sorted()
       
   161                 .map(s -> String.format("    uses %s;%n", s))
       
   162                 .forEach(sb::append);
       
   163         provides.entrySet().stream()
       
   164                 .sorted(Map.Entry.comparingByKey())
       
   165                 .flatMap(e -> e.getValue().stream().sorted()
       
   166                         .map(impl -> String.format("    provides %s with %s;%n", e.getKey(), impl)))
       
   167                 .forEach(sb::append);
       
   168         sb.append("}").append("\n");
       
   169         return sb.toString();
       
   170     }
       
   171 
       
   172     /**
       
   173      * Module Builder
       
   174      */
       
   175     static class Builder {
       
   176         private String name;
       
   177         final Set<Dependence> requires = new HashSet<>();
       
   178         final Map<String, Set<String>> exports = new HashMap<>();
       
   179         final Set<String> uses = new HashSet<>();
       
   180         final Map<String, Set<String>> provides = new HashMap<>();
       
   181 
       
   182         public Builder() {
       
   183         }
       
   184 
       
   185         public Builder name(String n) {
       
   186             name = n;
       
   187             return this;
       
   188         }
       
   189 
       
   190         public Builder require(String d, boolean reexport) {
       
   191             requires.add(new Dependence(d, reexport));
       
   192             return this;
       
   193         }
       
   194 
       
   195         public Builder export(String p) {
       
   196             Objects.requireNonNull(p);
       
   197             if (exports.containsKey(p)) {
       
   198                 throw new RuntimeException(name + " already exports " + p +
       
   199                         " " + exports.get(p));
       
   200             }
       
   201             return exportTo(p, Collections.emptySet());
       
   202         }
       
   203 
       
   204         public Builder exportTo(String p, String mn) {
       
   205             Objects.requireNonNull(p);
       
   206             Objects.requireNonNull(mn);
       
   207             Set<String> ms = exports.get(p);
       
   208             if (ms != null && ms.isEmpty()) {
       
   209                 throw new RuntimeException(name + " already has unqualified exports " + p);
       
   210             }
       
   211             exports.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
       
   212             return this;
       
   213         }
       
   214 
       
   215         public Builder exportTo(String p, Set<String> ms) {
       
   216             Objects.requireNonNull(p);
       
   217             Objects.requireNonNull(ms);
       
   218             if (exports.containsKey(p)) {
       
   219                 throw new RuntimeException(name + " already exports " + p +
       
   220                         " " + exports.get(p));
       
   221             }
       
   222             exports.put(p, new HashSet<>(ms));
       
   223             return this;
       
   224         }
       
   225 
       
   226         public Builder use(String cn) {
       
   227             uses.add(cn);
       
   228             return this;
       
   229         }
       
   230 
       
   231         public Builder provide(String s, String impl) {
       
   232             provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
       
   233             return this;
       
   234         }
       
   235 
       
   236         public Builder merge(Module m1, Module m2) {
       
   237             if (!m1.name().equals(m2.name())) {
       
   238                 throw new IllegalArgumentException(m1.name() + " != " + m2.name());
       
   239             }
       
   240             name = m1.name();
       
   241             // ## reexports
       
   242             requires.addAll(m1.requires());
       
   243             requires.addAll(m2.requires());
       
   244             Stream.concat(m1.exports().keySet().stream(), m2.exports().keySet().stream())
       
   245                     .distinct()
       
   246                     .forEach(pn -> {
       
   247                         Set<String> s1 = m2.exports().get(pn);
       
   248                         Set<String> s2 = m2.exports().get(pn);
       
   249                         if (s1 == null || s2 == null) {
       
   250                             exportTo(pn, s1 != null ? s1 : s2);
       
   251                         } else if (s1.isEmpty() || s2.isEmpty()) {
       
   252                             // unqualified exports
       
   253                             export(pn);
       
   254                         } else {
       
   255                             exportTo(pn, Stream.concat(s1.stream(), s2.stream())
       
   256                                                .collect(Collectors.toSet()));
       
   257                         }
       
   258                     });
       
   259             uses.addAll(m1.uses());
       
   260             uses.addAll(m2.uses());
       
   261             m1.provides().keySet().stream()
       
   262                     .forEach(s -> m1.provides().get(s).stream()
       
   263                             .forEach(impl -> provide(s, impl)));
       
   264             m2.provides().keySet().stream()
       
   265                     .forEach(s -> m2.provides().get(s).stream()
       
   266                             .forEach(impl -> provide(s, impl)));
       
   267             return this;
       
   268         }
       
   269 
       
   270         public Module build() {
       
   271             Module m = new Module(name, requires, exports, uses, provides);
       
   272             return m;
       
   273         }
       
   274 
       
   275         @Override
       
   276         public String toString() {
       
   277             return name != null ? name : "Unknown";
       
   278         }
       
   279     }
       
   280 }