jdk/make/src/classes/build/tools/module/Module.java
changeset 36511 9d0388c6b336
parent 26624 e6383382c939
--- a/jdk/make/src/classes/build/tools/module/Module.java	Tue Mar 15 13:48:26 2016 -0700
+++ b/jdk/make/src/classes/build/tools/module/Module.java	Thu Mar 17 19:04:16 2016 +0000
@@ -25,10 +25,17 @@
 
 package build.tools.module;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class Module {
-    static class Dependence {
+    public static class Dependence implements Comparable<Dependence> {
         final String name;
         final boolean reexport;
         Dependence(String name) {
@@ -43,6 +50,10 @@
             return name;
         }
 
+        public boolean reexport(){
+            return reexport;
+        }
+
         @Override
         public int hashCode() {
             int hash = 5;
@@ -55,20 +66,35 @@
             Dependence d = (Dependence)o;
             return this.name.equals(d.name) && this.reexport == d.reexport;
         }
+
+        @Override
+        public int compareTo(Dependence o) {
+            int rc = this.name.compareTo(o.name);
+            return rc != 0 ? rc : Boolean.compare(this.reexport, o.reexport);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("requires %s%s;",
+                                 reexport ? "public " : "", name);
+        }
     }
     private final String moduleName;
     private final Set<Dependence> requires;
     private final Map<String, Set<String>> exports;
-    private final Set<String> packages;
+    private final Set<String> uses;
+    private final Map<String, Set<String>> provides;
 
     private Module(String name,
-            Set<Dependence> requires,
-            Map<String, Set<String>> exports,
-            Set<String> packages) {
+                   Set<Dependence> requires,
+                   Map<String, Set<String>> exports,
+                   Set<String> uses,
+                   Map<String, Set<String>> provides) {
         this.moduleName = name;
         this.requires = Collections.unmodifiableSet(requires);
         this.exports = Collections.unmodifiableMap(exports);
-        this.packages = Collections.unmodifiableSet(packages);
+        this.uses  = Collections.unmodifiableSet(uses);
+        this.provides = Collections.unmodifiableMap(provides);
     }
 
     public String name() {
@@ -83,8 +109,12 @@
         return exports;
     }
 
-    public Set<String> packages() {
-        return packages;
+    public Set<String> uses() {
+        return uses;
+    }
+
+    public Map<String, Set<String>> provides() {
+        return provides;
     }
 
     @Override
@@ -95,8 +125,7 @@
         Module that = (Module) ob;
         return (moduleName.equals(that.moduleName)
                 && requires.equals(that.requires)
-                && exports.equals(that.exports)
-                && packages.equals(that.packages));
+                && exports.equals(that.exports));
     }
 
     @Override
@@ -104,43 +133,55 @@
         int hc = moduleName.hashCode();
         hc = hc * 43 + requires.hashCode();
         hc = hc * 43 + exports.hashCode();
-        hc = hc * 43 + packages.hashCode();
         return hc;
     }
 
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        sb.append("module ").append(moduleName).append(" {").append("\n");
-        requires.stream().sorted().forEach(d ->
-                sb.append(String.format("   requires %s%s%n", d.reexport ? "public " : "", d.name)));
-        exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
+        sb.append(String.format("module %s {%n", moduleName));
+        requires.stream()
+                .sorted()
+                .map(d -> String.format("    requires %s%s;%n", d.reexport ? "public " : "", d.name))
+                .forEach(sb::append);
+        exports.entrySet().stream()
+                .filter(e -> e.getValue().isEmpty())
+                .sorted(Map.Entry.comparingByKey())
+                .map(e -> String.format("    exports %s;%n", e.getKey()))
+                .forEach(sb::append);
+        exports.entrySet().stream()
+                .filter(e -> !e.getValue().isEmpty())
                 .sorted(Map.Entry.comparingByKey())
-                .forEach(e -> sb.append(String.format("   exports %s%n", e.getKey())));
-        exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
+                .map(e -> String.format("    exports %s to%n%s;%n", e.getKey(),
+                        e.getValue().stream().sorted()
+                                .map(mn -> String.format("        %s", mn))
+                                .collect(Collectors.joining(",\n"))))
+                .forEach(sb::append);
+        uses.stream().sorted()
+                .map(s -> String.format("    uses %s;%n", s))
+                .forEach(sb::append);
+        provides.entrySet().stream()
                 .sorted(Map.Entry.comparingByKey())
-                .forEach(e -> sb.append(String.format("   exports %s to %s%n", e.getKey(), e.getValue())));
-        packages.stream().sorted().forEach(pn -> sb.append(String.format("   includes %s%n", pn)));
-        sb.append("}");
+                .flatMap(e -> e.getValue().stream().sorted()
+                        .map(impl -> String.format("    provides %s with %s;%n", e.getKey(), impl)))
+                .forEach(sb::append);
+        sb.append("}").append("\n");
         return sb.toString();
     }
 
+    /**
+     * Module Builder
+     */
     static class Builder {
         private String name;
-        private final Set<Dependence> requires = new HashSet<>();
-        private final Map<String, Set<String>> exports = new HashMap<>();
-        private final Set<String> packages = new HashSet<>();
+        final Set<Dependence> requires = new HashSet<>();
+        final Map<String, Set<String>> exports = new HashMap<>();
+        final Set<String> uses = new HashSet<>();
+        final Map<String, Set<String>> provides = new HashMap<>();
 
         public Builder() {
         }
 
-        public Builder(Module module) {
-            name = module.name();
-            requires.addAll(module.requires());
-            exports.putAll(module.exports());
-            packages.addAll(module.packages());
-        }
-
         public Builder name(String n) {
             name = n;
             return this;
@@ -151,28 +192,89 @@
             return this;
         }
 
-        public Builder include(String p) {
-            packages.add(p);
-            return this;
+        public Builder export(String p) {
+            Objects.requireNonNull(p);
+            if (exports.containsKey(p)) {
+                throw new RuntimeException(name + " already exports " + p +
+                        " " + exports.get(p));
+            }
+            return exportTo(p, Collections.emptySet());
         }
 
-        public Builder export(String p) {
-            return exportTo(p, Collections.emptySet());
+        public Builder exportTo(String p, String mn) {
+            Objects.requireNonNull(p);
+            Objects.requireNonNull(mn);
+            Set<String> ms = exports.get(p);
+            if (ms != null && ms.isEmpty()) {
+                throw new RuntimeException(name + " already has unqualified exports " + p);
+            }
+            exports.computeIfAbsent(p, _k -> new HashSet<>()).add(mn);
+            return this;
         }
 
         public Builder exportTo(String p, Set<String> ms) {
             Objects.requireNonNull(p);
             Objects.requireNonNull(ms);
             if (exports.containsKey(p)) {
-                throw new RuntimeException(name + " already exports " + p);
+                throw new RuntimeException(name + " already exports " + p +
+                        " " + exports.get(p));
             }
             exports.put(p, new HashSet<>(ms));
             return this;
         }
 
+        public Builder use(String cn) {
+            uses.add(cn);
+            return this;
+        }
+
+        public Builder provide(String s, String impl) {
+            provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl);
+            return this;
+        }
+
+        public Builder merge(Module m1, Module m2) {
+            if (!m1.name().equals(m2.name())) {
+                throw new IllegalArgumentException(m1.name() + " != " + m2.name());
+            }
+            name = m1.name();
+            // ## reexports
+            requires.addAll(m1.requires());
+            requires.addAll(m2.requires());
+            Stream.concat(m1.exports().keySet().stream(), m2.exports().keySet().stream())
+                    .distinct()
+                    .forEach(pn -> {
+                        Set<String> s1 = m2.exports().get(pn);
+                        Set<String> s2 = m2.exports().get(pn);
+                        if (s1 == null || s2 == null) {
+                            exportTo(pn, s1 != null ? s1 : s2);
+                        } else if (s1.isEmpty() || s2.isEmpty()) {
+                            // unqualified exports
+                            export(pn);
+                        } else {
+                            exportTo(pn, Stream.concat(s1.stream(), s2.stream())
+                                               .collect(Collectors.toSet()));
+                        }
+                    });
+            uses.addAll(m1.uses());
+            uses.addAll(m2.uses());
+            m1.provides().keySet().stream()
+                    .forEach(s -> m1.provides().get(s).stream()
+                            .forEach(impl -> provide(s, impl)));
+            m2.provides().keySet().stream()
+                    .forEach(s -> m2.provides().get(s).stream()
+                            .forEach(impl -> provide(s, impl)));
+            return this;
+        }
+
         public Module build() {
-            Module m = new Module(name, requires, exports, packages);
+            Module m = new Module(name, requires, exports, uses, provides);
             return m;
         }
+
+        @Override
+        public String toString() {
+            return name != null ? name : "Unknown";
+        }
     }
 }