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.*;
  29 
  30 public class Module {
  31     static class Dependence {
  32         final String name;
  33         final boolean reexport;
  34         Dependence(String name) {
  35             this(name, false);
  36         }
  37         Dependence(String name, boolean reexport) {
  38             this.name = name;
  39             this.reexport = reexport;
  40         }
  41 
  42         public String name() {
  43             return name;
  44         }
  45 
  46         @Override
  47         public int hashCode() {
  48             int hash = 5;
  49             hash = 11 * hash + Objects.hashCode(this.name);
  50             hash = 11 * hash + (this.reexport ? 1 : 0);
  51             return hash;
  52         }
  53 
  54         public boolean equals(Object o) {
  55             Dependence d = (Dependence)o;
  56             return this.name.equals(d.name) && this.reexport == d.reexport;
  57         }
  58     }
  59     private final String moduleName;
  60     private final Set<Dependence> requires;
  61     private final Map<String, Set<String>> exports;
  62     private final Set<String> packages;
  63 
  64     private Module(String name,
  65             Set<Dependence> requires,
  66             Map<String, Set<String>> exports,
  67             Set<String> packages) {
  68         this.moduleName = name;
  69         this.requires = Collections.unmodifiableSet(requires);
  70         this.exports = Collections.unmodifiableMap(exports);
  71         this.packages = Collections.unmodifiableSet(packages);
  72     }
  73 
  74     public String name() {
  75         return moduleName;
  76     }
  77 
  78     public Set<Dependence> requires() {
  79         return requires;
  80     }
  81 
  82     public Map<String, Set<String>> exports() {
  83         return exports;
  84     }
  85 
  86     public Set<String> packages() {
  87         return packages;
  88     }
  89 
  90     @Override
  91     public boolean equals(Object ob) {
  92         if (!(ob instanceof Module)) {
  93             return false;
  94         }
  95         Module that = (Module) ob;
  96         return (moduleName.equals(that.moduleName)
  97                 && requires.equals(that.requires)
  98                 && exports.equals(that.exports)
  99                 && packages.equals(that.packages));
 100     }
 101 
 102     @Override
 103     public int hashCode() {
 104         int hc = moduleName.hashCode();
 105         hc = hc * 43 + requires.hashCode();
 106         hc = hc * 43 + exports.hashCode();
 107         hc = hc * 43 + packages.hashCode();
 108         return hc;
 109     }
 110 
 111     @Override
 112     public String toString() {
 113         StringBuilder sb = new StringBuilder();
 114         sb.append("module ").append(moduleName).append(" {").append("\n");
 115         requires.stream().sorted().forEach(d ->
 116                 sb.append(String.format("   requires %s%s%n", d.reexport ? "public " : "", d.name)));
 117         exports.entrySet().stream().filter(e -> e.getValue().isEmpty())
 118                 .sorted(Map.Entry.comparingByKey())
 119                 .forEach(e -> sb.append(String.format("   exports %s%n", e.getKey())));
 120         exports.entrySet().stream().filter(e -> !e.getValue().isEmpty())
 121                 .sorted(Map.Entry.comparingByKey())
 122                 .forEach(e -> sb.append(String.format("   exports %s to %s%n", e.getKey(), e.getValue())));
 123         packages.stream().sorted().forEach(pn -> sb.append(String.format("   includes %s%n", pn)));
 124         sb.append("}");
 125         return sb.toString();
 126     }
 127 
 128     static class Builder {
 129         private String name;
 130         private final Set<Dependence> requires = new HashSet<>();
 131         private final Map<String, Set<String>> exports = new HashMap<>();
 132         private final Set<String> packages = new HashSet<>();
 133 
 134         public Builder() {
 135         }
 136 
 137         public Builder(Module module) {
 138             name = module.name();
 139             requires.addAll(module.requires());
 140             exports.putAll(module.exports());
 141             packages.addAll(module.packages());
 142         }
 143 
 144         public Builder name(String n) {
 145             name = n;
 146             return this;
 147         }
 148 
 149         public Builder require(String d, boolean reexport) {
 150             requires.add(new Dependence(d, reexport));
 151             return this;
 152         }
 153 
 154         public Builder include(String p) {
 155             packages.add(p);
 156             return this;
 157         }
 158 
 159         public Builder export(String p) {
 160             return exportTo(p, Collections.emptySet());
 161         }
 162 
 163         public Builder exportTo(String p, Set<String> ms) {
 164             Objects.requireNonNull(p);
 165             Objects.requireNonNull(ms);
 166             if (exports.containsKey(p)) {
 167                 throw new RuntimeException(name + " already exports " + p);
 168             }
 169             exports.put(p, new HashSet<>(ms));
 170             return this;
 171         }
 172 
 173         public Module build() {
 174             Module m = new Module(name, requires, exports, packages);
 175             return m;
 176         }
 177     }
 178 }