make/tools/classanalyzer/src/com/sun/classanalyzer/ModuleInfo.java

Print this page




  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 com.sun.classanalyzer;
  24 
  25 import java.util.*;
  26 
  27 /**
  28  * Information about a module.  ModuleInfo.toString() returns
  29  * a string representation of the module-info.java source file.
  30  *
  31  * @author Mandy Chung
  32  */
  33 public class ModuleInfo {
  34 
  35     private final Module module;
  36     private final String version;
  37     private final Set<PackageInfo> packages;
  38     private final Set<Dependence> requires;
  39     private final Set<Module> permits;
  40 
  41     ModuleInfo(Module m, String version,
  42             Collection<PackageInfo> packages,
  43             Collection<Dependence> reqs,
  44             Collection<Module> permits) {
  45         this.module = m;
  46         this.version = version;
  47         this.packages = new TreeSet<PackageInfo>(packages);
  48         this.permits = new TreeSet<Module>(permits);
  49         this.requires = new TreeSet<Dependence>();
  50         // filter non-top level module
  51         for (Dependence d : reqs) {
  52             if (d.getModule().isTopLevel()) {
  53                 requires.add(d);
  54             }
  55         }
  56     }
  57 
  58     public Module getModule() {
  59         return module;
  60     }
  61 
  62     /**
  63      * This module's identifier
  64      */
  65     public String name() {
  66         return module.name();
  67     }
  68 
  69     public String id() {
  70         return module.name() + " @ " + version;
  71     }
  72 
  73     public Set<PackageInfo> packages() {
  74         return Collections.unmodifiableSet(packages);
  75     }
  76 
  77     /**
  78      * The dependences of this module
  79      */
  80     public Set<Dependence> requires() {
  81         return Collections.unmodifiableSet(requires);
  82     }
  83 
  84     /**
  85      * The modules that are permitted to require this module
  86      */
  87     public Set<Module> permits() {
  88         return Collections.unmodifiableSet(permits);
  89     }
  90 
  91     public void addPermit(Module m) {
  92         permits.add(m);
  93     }
  94 


 126 
 127     private synchronized Set<String> reexports() {
 128         if (reexports != null) {
 129             return reexports;
 130         }
 131 
 132         final Module m = module;
 133         Set<Module> deps = dependences(new Dependence.Filter() {
 134 
 135             @Override
 136             public boolean accept(Dependence d) {
 137                 // filter itself
 138                 return d.isPublic();
 139             }
 140         });
 141 
 142         reexports = new TreeSet<String>();
 143         for (Module dm : deps) {
 144             if (dm != module) {
 145                 // exports all local packages
 146                 for (PackageInfo p : dm.getModuleInfo().packages) {
 147                     if (PackageInfo.isExportedPackage(p.pkgName)) {
 148                         reexports.add(p.pkgName + ".*");
 149                     }
 150                 }
 151                 reexports.addAll(dm.getModuleInfo().reexports());
 152             }
 153         }
 154         return reexports;
 155     }





 156     private static final String INDENT = "    ";
 157 

 158     /**
 159      * Returns a string representation of module-info.java for
 160      * this module.
 161      */
 162     @Override
 163     public String toString() {
 164         StringBuilder sb = new StringBuilder();
 165         sb.append(String.format("module %s {%n", id()));
 166 
 167         for (Dependence d : requires()) {
 168             String mods = "";
 169             for (Dependence.Modifier mod : d.mods) {
 170                 if (mod != Dependence.Modifier.PUBLIC) {
 171                     mods += mod.toString() + " ";
 172                 }
 173             }
 174             sb.append(String.format("%srequires %s%s;%n", INDENT,
 175                                     mods,
 176                                     d.getModule().getModuleInfo().id()));
 177         }
 178 
 179         String permits = INDENT + "permits ";
 180         int i = 0;
 181         for (Module pm : permits()) {
 182             if (i > 0) {
 183                 permits += ", ";
 184                 if ((i % 5) == 0) {
 185                     permits += "\n" + INDENT + "        "; // "permits"
 186                 }
 187             }
 188             permits += pm.name();
 189             i++;
 190         }
 191 
 192         if (permits().size() > 0) {
 193             sb.append(permits).append(";\n");
 194         }
 195         if (module.mainClass() != null) {
 196             sb.append(String.format("%sclass %s;%n", INDENT, mainClass()));
 197         }
 198 








 199         Set<Module> modules = dependences(new Dependence.Filter() {
 200 
 201             @Override
 202             public boolean accept(Dependence d) {
 203                 // filter itself
 204                 return d.isPublic();
 205             }
 206         });
 207 
 208         // explicit exports in the given config file
 209         Set<String> cexports = new TreeSet<String>();
 210         for (Module m : modules) {
 211             cexports.addAll(m.config().exports());
 212         }
 213 
 214         if (cexports.size() > 0) {
 215             sb.append("\n" + INDENT + "// explicit exports\n");
 216             for (String e : cexports) {
 217                 sb.append(String.format("%sexport %s;%n", INDENT, e));
 218             }
 219         }
 220 
 221         // exports all local packages
 222         Set<String> pkgs = new TreeSet<String>();
 223         for (PackageInfo pi : packages) {
 224             String p = pi.pkgName;
 225             if (module.exportAllPackages() || PackageInfo.isExportedPackage(p))
 226                 pkgs.add(p);
 227         }
 228  
 229         if (pkgs.size() > 0) {
 230             sb.append(String.format("%n%s// exports %s packages%n", INDENT,
 231                                     module.exportAllPackages() ? "all local" : "supported"));
 232             for (String p : pkgs) {
 233                 sb.append(String.format("%sexport %s.*;%n", INDENT, p));
 234             }
 235         }
 236 
 237         // reexports
 238         if (reexports().size() > 0) {
 239             Set<String> rexports = new TreeSet<String>();
 240             if (modules.size() == 2) {
 241                 // special case?
 242                 rexports.addAll(reexports());
 243             } else {
 244                 for (String e : reexports()) {
 245                     int j = e.indexOf('.');
 246                     rexports.add(e.substring(0, j) + ".**");
 247                 }
 248             }
 249             sb.append("\n" + INDENT + "// reexports\n");
 250             for (String p : rexports) {
 251                 sb.append(String.format("%sexport %s;%n", INDENT, p));
 252             }
 253         }
 254 
 255         sb.append("}\n");
 256         return sb.toString();
 257     }
 258 
 259     static class Dependence implements Comparable<Dependence> {
 260 
 261         static enum Modifier {
 262 
 263             PUBLIC("public"),
 264             OPTIONAL("optional"),
 265             LOCAL("local");
 266             private final String name;
 267 
 268             Modifier(String n) {
 269                 this.name = n;
 270             }
 271 
 272             @Override
 273             public String toString() {
 274                 return name;
 275             }
 276         }
 277         private final String id;
 278         private EnumSet<Modifier> mods;
 279         private Module sm = null;
 280 
 281         public Dependence(Module sm) {
 282             this(sm, false);
 283         }
 284 
 285         public Dependence(Module sm, boolean optional) {
 286             this(sm, modifier(optional));
 287         }
 288 
 289         public Dependence(Klass from, Klass to, boolean optional) {
 290             this(to.getModule(), modifier(optional));
 291         }
 292 
 293         public Dependence(Module sm, EnumSet<Modifier> mods) {
 294             this.sm = sm.group();
 295             this.id = this.sm.name();
 296             this.mods = mods;
 297         }
 298 
 299         public Dependence(String name, boolean optional) {
 300             this(name, optional, false, false);
 301         }
 302 
 303         public Dependence(String name, boolean optional, boolean reexport, boolean local) {
 304             Set<Modifier> ms = new TreeSet<Modifier>();
 305             if (optional) {
 306                 ms.add(Modifier.OPTIONAL);
 307             }
 308             if (reexport) {
 309                 ms.add(Modifier.PUBLIC);
 310             }
 311             if (local) {
 312                 ms.add(Modifier.LOCAL);
 313             }
 314             this.id = name;
 315             this.mods = ms.isEmpty()
 316                     ? EnumSet.noneOf(Modifier.class)
 317                     : EnumSet.copyOf(ms);
 318         }
 319 
 320         private static EnumSet<Modifier> modifier(boolean optional) {
 321             return optional ? EnumSet.of(Modifier.OPTIONAL)
 322                     : EnumSet.noneOf(Modifier.class);
 323         }
 324 
 325         synchronized Module getModule() {
 326             if (sm == null) {
 327                 Module m = Module.findModule(id);
 328                 if (m == null) {
 329                     throw new RuntimeException("Module " + id + " doesn't exist");
 330                 }
 331                 sm = m.group();
 332             }
 333             return sm;
 334         }
 335 
 336         public boolean isOptional() {
 337             return mods.contains(Modifier.OPTIONAL);
 338         }
 339 
 340         public boolean isLocal() {
 341             return mods.contains(Modifier.LOCAL);
 342         }
 343 
 344         public boolean isPublic() {
 345             return mods.contains(Modifier.PUBLIC);
 346         }
 347 
 348         public void addModifier(Modifier e) {
 349             mods.add(e);
 350         }
 351 
 352         public void update(Dependence d) {
 353             // static dependence overrides the optional




  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 com.sun.classanalyzer;
  24 
  25 import java.util.*;
  26 
  27 /**
  28  * Information about a module.  ModuleInfo.toString() returns
  29  * a string representation of the module-info.java source file.
  30  *
  31  * @author Mandy Chung
  32  */
  33 public class ModuleInfo {
  34 
  35     private final Module module;


  36     private final Set<Dependence> requires;
  37     private final Set<Module> permits;
  38 
  39     ModuleInfo(Module m,

  40             Collection<Dependence> reqs,
  41             Collection<Module> permits) {
  42         this.module = m;


  43         this.permits = new TreeSet<Module>(permits);
  44         this.requires = new TreeSet<Dependence>();
  45         // filter non-top level module
  46         for (Dependence d : reqs) {
  47             if (d.getModule().isTopLevel()) {
  48                 requires.add(d);
  49             }
  50         }
  51     }
  52 
  53     public Module getModule() {
  54         return module;
  55     }
  56 
  57     /**
  58      * This module's identifier
  59      */
  60     public String name() {
  61         return module.name();
  62     }
  63 
  64     public String id() {
  65         return module.name() + " @ " + module.version();




  66     }
  67 
  68     /**
  69      * The dependences of this module
  70      */
  71     public Set<Dependence> requires() {
  72         return Collections.unmodifiableSet(requires);
  73     }
  74 
  75     /**
  76      * The modules that are permitted to require this module
  77      */
  78     public Set<Module> permits() {
  79         return Collections.unmodifiableSet(permits);
  80     }
  81 
  82     public void addPermit(Module m) {
  83         permits.add(m);
  84     }
  85 


 117 
 118     private synchronized Set<String> reexports() {
 119         if (reexports != null) {
 120             return reexports;
 121         }
 122 
 123         final Module m = module;
 124         Set<Module> deps = dependences(new Dependence.Filter() {
 125 
 126             @Override
 127             public boolean accept(Dependence d) {
 128                 // filter itself
 129                 return d.isPublic();
 130             }
 131         });
 132 
 133         reexports = new TreeSet<String>();
 134         for (Module dm : deps) {
 135             if (dm != module) {
 136                 // exports all local packages
 137                 for (PackageInfo p : dm.packages()) {
 138                     if (PackageInfo.isExportedPackage(p.pkgName)) {
 139                         reexports.add(p.pkgName + ".*");
 140                     }
 141                 }
 142                 reexports.addAll(dm.getModuleInfo().reexports());
 143             }
 144         }
 145         return reexports;
 146     }
 147     
 148     // a system property to use "requires public" to reexport
 149     // instead of the "exports" statement
 150     private static final boolean requiresPublic =
 151             Boolean.getBoolean("classanalyzer.requiresPublic");
 152     private static final String INDENT = "    ";
 153 
 154 
 155     /**
 156      * Returns a string representation of module-info.java for
 157      * this module.
 158      */
 159     @Override
 160     public String toString() {
 161         StringBuilder sb = new StringBuilder();
 162         sb.append(String.format("module %s {%n", id()));
 163 
 164         for (Dependence d : requires()) {
 165             String mods = "";
 166             for (Dependence.Modifier mod : d.mods) {
 167                 if (requiresPublic || mod != Dependence.Modifier.PUBLIC) {
 168                     mods += mod.toString() + " ";
 169                 }
 170             }
 171             sb.append(String.format("%srequires %s%s;%n", INDENT,
 172                                     mods,
 173                                     d.getModule().getModuleInfo().id()));
 174         }
 175 
 176         String permits = INDENT + "permits ";
 177         int i = 0;
 178         for (Module pm : permits()) {
 179             if (i > 0) {
 180                 permits += ", ";
 181                 if ((i % 5) == 0) {
 182                     permits += "\n" + INDENT + "        "; // "permits"
 183                 }
 184             }
 185             permits += pm.name();
 186             i++;
 187         }
 188 
 189         if (permits().size() > 0) {
 190             sb.append(permits).append(";\n");
 191         }
 192         if (module.mainClass() != null) {
 193             sb.append(String.format("%sclass %s;%n", INDENT, mainClass()));
 194         }
 195         
 196         if (!requiresPublic)
 197             printExports(sb);
 198         
 199         sb.append("}\n");
 200         return sb.toString();
 201     }
 202     
 203     private void printExports(StringBuilder sb) {
 204         Set<Module> modules = dependences(new Dependence.Filter() {
 205 
 206             @Override
 207             public boolean accept(Dependence d) {
 208                 // filter itself
 209                 return d.isPublic();
 210             }
 211         });
 212 
 213         // explicit exports in the given config file
 214         Set<String> cexports = new TreeSet<String>();
 215         for (Module m : modules) {
 216             cexports.addAll(m.config().exports());
 217         }
 218 
 219         if (cexports.size() > 0) {
 220             sb.append("\n" + INDENT + "// explicit exports\n");
 221             for (String e : cexports) {
 222                 sb.append(String.format("%sexport %s;%n", INDENT, e));
 223             }
 224         }
 225 
 226         // exports all local packages
 227         Set<String> pkgs = new TreeSet<String>();
 228         for (PackageInfo pi : module.packages()) {
 229             String p = pi.pkgName;
 230             if (module.exportAllPackages() || PackageInfo.isExportedPackage(p))
 231                 pkgs.add(p);
 232         }
 233  
 234         if (pkgs.size() > 0) {
 235             sb.append(String.format("%n%s// exports %s packages%n", INDENT,
 236                                     module.exportAllPackages() ? "all local" : "supported"));
 237             for (String p : pkgs) {
 238                 sb.append(String.format("%sexport %s.*;%n", INDENT, p));
 239             }
 240         }
 241 
 242         // reexports
 243         if (reexports().size() > 0) {
 244             Set<String> rexports = new TreeSet<String>();
 245             if (modules.size() == 2) {
 246                 // special case?
 247                 rexports.addAll(reexports());
 248             } else {
 249                 for (String e : reexports()) {
 250                     int j = e.indexOf('.');
 251                     rexports.add(e.substring(0, j) + ".**");
 252                 }
 253             }
 254             sb.append("\n" + INDENT + "// reexports\n");
 255             for (String p : rexports) {
 256                 sb.append(String.format("%sexport %s;%n", INDENT, p));
 257             }
 258         }



 259     }
 260 
 261     static class Dependence implements Comparable<Dependence> {
 262 
 263         static enum Modifier {
 264 
 265             PUBLIC("public"),
 266             OPTIONAL("optional"),
 267             LOCAL("local");
 268             private final String name;
 269 
 270             Modifier(String n) {
 271                 this.name = n;
 272             }
 273 
 274             @Override
 275             public String toString() {
 276                 return name;
 277             }
 278         }
 279         final String id;
 280         private EnumSet<Modifier> mods;
 281         private Module dm = null;
 282 
 283         public Dependence(Module dm) {
 284             this(dm, false);
 285         }
 286 
 287         public Dependence(Module dm, boolean optional) {
 288             this(dm, modifier(optional));
 289         }
 290 
 291         public Dependence(Module dm, EnumSet<Modifier> mods) {
 292             this.dm = dm.group();
 293             this.id = dm.name();




 294             this.mods = mods;
 295         }
 296 
 297         public Dependence(String name, boolean optional) {
 298             this(name, optional, false, false);
 299         }
 300 
 301         public Dependence(String name, boolean optional, boolean reexport, boolean local) {
 302             Set<Modifier> ms = new TreeSet<Modifier>();
 303             if (optional) {
 304                 ms.add(Modifier.OPTIONAL);
 305             }
 306             if (reexport) {
 307                 ms.add(Modifier.PUBLIC);
 308             }
 309             if (local) {
 310                 ms.add(Modifier.LOCAL);
 311             }
 312             this.id = name;
 313             this.mods = ms.isEmpty()
 314                     ? EnumSet.noneOf(Modifier.class)
 315                     : EnumSet.copyOf(ms);
 316         }
 317 
 318         private static EnumSet<Modifier> modifier(boolean optional) {
 319             return optional ? EnumSet.of(Modifier.OPTIONAL)
 320                     : EnumSet.noneOf(Modifier.class);
 321         }
 322 
 323         void setModule(Module m) {
 324             assert dm == null && m != null;
 325             dm = m.group();


 326         }
 327         
 328         Module getModule() {
 329             return dm;
 330         }
 331 
 332         public boolean isOptional() {
 333             return mods.contains(Modifier.OPTIONAL);
 334         }
 335 
 336         public boolean isLocal() {
 337             return mods.contains(Modifier.LOCAL);
 338         }
 339 
 340         public boolean isPublic() {
 341             return mods.contains(Modifier.PUBLIC);
 342         }
 343 
 344         public void addModifier(Modifier e) {
 345             mods.add(e);
 346         }
 347 
 348         public void update(Dependence d) {
 349             // static dependence overrides the optional