src/jdk.compiler/share/classes/com/sun/tools/sjavac/Package.java

Print this page
rev 2819 : imported patch my-classpath-deps-00


  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 com.sun.tools.sjavac;
  27 
  28 import java.io.File;
  29 import java.net.URI;
  30 import java.util.ArrayList;
  31 import java.util.Collections;
  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Iterator;
  35 import java.util.List;
  36 import java.util.Map;
  37 import java.util.Set;





  38 import com.sun.tools.javac.util.Assert;

  39 
  40 /**
  41  * The Package class maintains meta information about a package.
  42  * For example its sources, dependents,its pubapi and its artifacts.
  43  *
  44  * It might look odd that we track dependents/pubapi/artifacts on
  45  * a package level, but it makes sense since recompiling a full package
  46  * takes as long as recompiling a single java file in that package,
  47  * if you take into account the startup time of the jvm.
  48  *
  49  * Also the dependency information will be much smaller (good for the javac_state file size)
  50  * and it simplifies tracking artifact generation, you do not always know from which
  51  * source a class file was generated, but you always know which package it belongs to.
  52  *
  53  * It is also educational to see package dependencies triggering recompilation of
  54  * other packages. Even though the recompilation was perhaps not necessary,
  55  * the visible recompilation of the dependent packages indicates how much circular
  56  * dependencies your code has.
  57  *
  58  *  <p><b>This is NOT part of any supported API.
  59  *  If you write code that depends on this, you do so at your own risk.
  60  *  This code and its internal interfaces are subject to change or
  61  *  deletion without notice.</b>
  62  */
  63 public class Package implements Comparable<Package> {
  64     // The module this package belongs to. (There is a legacy module with an empty string name,
  65     // used for all legacy sources.)
  66     private Module mod;
  67     // Name of this package, module:pkg
  68     // ex1 jdk.base:java.lang
  69     // ex2 :java.lang (when in legacy mode)
  70     private String name;
  71     // The directory path to the package. If the package belongs to a module,
  72     // then that module's file system name is part of the path.
  73     private String dirname;
  74     // This package depends on these packages.
  75     private Set<String> dependencies = new HashSet<>();
  76     // This package has the following dependents, that depend on this package.
  77     private Set<String> dependents = new HashSet<>();






  78     // This is the public api of this package.
  79     private List<String> pubapi = new ArrayList<>();
  80     // Map from source file name to Source info object.
  81     private Map<String,Source> sources = new HashMap<>();
  82     // This package generated these artifacts.
  83     private Map<String,File> artifacts = new HashMap<>();
  84 
  85     public Package(Module m, String n) {
  86         int c = n.indexOf(":");
  87         Assert.check(c != -1);
  88         String mn = n.substring(0,c);
  89         Assert.check(m.name().equals(m.name()));
  90         name = n;
  91         dirname = n.replace('.', File.separatorChar);
  92         if (m.name().length() > 0) {
  93             // There is a module here, prefix the module dir name to the path.
  94             dirname = m.dirname()+File.separatorChar+dirname;
  95         }
  96     }
  97 
  98     public Module mod() { return mod; }
  99     public String name() { return name; }
 100     public String dirname() { return dirname; }
 101     public Map<String,Source> sources() { return sources; }
 102     public Map<String,File> artifacts() { return artifacts; }
 103     public List<String> pubapi() { return pubapi; }



 104 
 105     public Set<String> dependencies() { return dependencies; }
 106     public Set<String> dependents() { return dependents; }
 107 
 108     @Override
 109     public boolean equals(Object o) {
 110         return (o instanceof Package) && name.equals(((Package)o).name);
 111     }
 112 
 113     @Override
 114     public int hashCode() {
 115         return name.hashCode();
 116     }
 117 
 118     @Override
 119     public int compareTo(Package o) {
 120         return name.compareTo(o.name);
 121     }
 122 
 123     public void addSource(Source s) {
 124         sources.put(s.file().getPath(), s);
 125     }
 126 
 127     public void addDependency(String d) {
 128         dependencies.add(d);




 129     }
 130 
 131     public void addDependent(String d) {
 132         dependents.add(d);





 133     }
 134 
 135     public void addPubapi(String p) {
 136         pubapi.add(p);
 137     }
 138 
 139     /**
 140      * Check if we have knowledge in the javac state that
 141      * describe the results of compiling this package before.
 142      */
 143     public boolean existsInJavacState() {
 144         return artifacts.size() > 0 || pubapi.size() > 0;
 145     }
 146 
 147     public static List<String> pubapiToList(String ps)
 148     {
 149         String[] lines = ps.split("\n");
 150         List<String> r = new ArrayList<>();
 151         for (String l : lines) {
 152             r.add(l);
 153         }
 154         return r;
 155     }
 156 
 157     public boolean hasPubapiChanged(List<String> ps) {
 158         Iterator<String> i = ps.iterator();
 159         Iterator<String> j = pubapi.iterator();
 160         int line = 0;
 161         while (i.hasNext() && j.hasNext()) {
 162             String is = i.next();
 163             String js = j.next();
 164             if (!is.equals(js)) {
 165                 Log.debug("Change in pubapi for package "+name+" line "+line);
 166                 Log.debug("Old: "+js);
 167                 Log.debug("New: "+is);
 168                 return true;
 169             }
 170             line++;
 171         }
 172         if ((i.hasNext() && !j.hasNext() ) ||
 173             (!i.hasNext() && j.hasNext())) {
 174             Log.debug("Change in pubapi for package "+name);
 175             if (i.hasNext()) {
 176                 Log.debug("New has more lines!");
 177             } else {
 178                 Log.debug("Old has more lines!");
 179             }
 180             return true;
 181         }
 182         return false;
 183     }
 184 
 185     public void setPubapi(List<String> ps) {
 186         pubapi = ps;
 187     }
 188 
 189     public void setDependencies(Set<String> ds) {
 190         dependencies = ds;
 191     }
 192 
 193     public void save(StringBuilder b) {
 194         b.append("P ").append(name).append("\n");
 195         Source.saveSources(sources, b);
 196         saveDependencies(b);
 197         savePubapi(b);
 198         saveArtifacts(b);
 199     }
 200 
 201     static public Package load(Module module, String l) {
 202         String name = l.substring(2);
 203         return new Package(module, name);
 204     }
 205 
 206     public void loadDependency(String l) {
 207         String n = l.substring(2);
 208         addDependency(n);
 209     }
 210 
 211     public void loadPubapi(String l) {
 212         String pi = l.substring(2);
 213         addPubapi(pi);


 214     }
 215 
 216     public void saveDependencies(StringBuilder b) {
 217         List<String> sorted_dependencies = new ArrayList<>();
 218         for (String key : dependencies) {
 219             sorted_dependencies.add(key);
 220         }
 221         Collections.sort(sorted_dependencies);
 222         for (String a : sorted_dependencies) {
 223             b.append("D "+a+"\n");
 224         }
 225     }
 226 
 227     public void savePubapi(StringBuilder b) {
 228         for (String l : pubapi) {
 229             b.append("I "+l+"\n");
 230         }

 231     }
 232 
 233     public static void savePackages(Map<String,Package> packages, StringBuilder b) {
 234         List<String> sorted_packages = new ArrayList<>();
 235         for (String key : packages.keySet() ) {
 236             sorted_packages.add(key);
 237         }
 238         Collections.sort(sorted_packages);
 239         for (String s : sorted_packages) {
 240             Package p = packages.get(s);
 241             p.save(b);
 242         }
 243     }
 244 
 245     public void addArtifact(String a) {
 246         artifacts.put(a, new File(a));
 247     }
 248 
 249     public void addArtifact(File f) {
 250         artifacts.put(f.getPath(), f);




  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 com.sun.tools.sjavac;
  27 
  28 import java.io.File;
  29 import java.net.URI;
  30 import java.util.ArrayList;
  31 import java.util.Collections;
  32 import java.util.HashMap;
  33 import java.util.HashSet;

  34 import java.util.List;
  35 import java.util.Map;
  36 import java.util.Set;
  37 import java.util.TreeMap;
  38 import java.util.regex.Matcher;
  39 import java.util.regex.Pattern;
  40 import java.util.stream.Stream;
  41 
  42 import com.sun.tools.javac.util.Assert;
  43 import com.sun.tools.sjavac.pubapi.PubApi;
  44 
  45 /**
  46  * The Package class maintains meta information about a package.
  47  * For example its sources, dependents,its pubapi and its artifacts.
  48  *
  49  * It might look odd that we track dependents/pubapi/artifacts on
  50  * a package level, but it makes sense since recompiling a full package
  51  * takes as long as recompiling a single java file in that package,
  52  * if you take into account the startup time of the jvm.
  53  *
  54  * Also the dependency information will be much smaller (good for the javac_state file size)
  55  * and it simplifies tracking artifact generation, you do not always know from which
  56  * source a class file was generated, but you always know which package it belongs to.
  57  *
  58  * It is also educational to see package dependencies triggering recompilation of
  59  * other packages. Even though the recompilation was perhaps not necessary,
  60  * the visible recompilation of the dependent packages indicates how much circular
  61  * dependencies your code has.
  62  *
  63  *  <p><b>This is NOT part of any supported API.
  64  *  If you write code that depends on this, you do so at your own risk.
  65  *  This code and its internal interfaces are subject to change or
  66  *  deletion without notice.</b>
  67  */
  68 public class Package implements Comparable<Package> {
  69     // The module this package belongs to. (There is a legacy module with an empty string name,
  70     // used for all legacy sources.)
  71     private Module mod;
  72     // Name of this package, module:pkg
  73     // ex1 jdk.base:java.lang
  74     // ex2 :java.lang (when in legacy mode)
  75     private String name;
  76     // The directory path to the package. If the package belongs to a module,
  77     // then that module's file system name is part of the path.
  78     private String dirname;


  79     // This package has the following dependents, that depend on this package.
  80     private Set<String> dependents = new HashSet<>();
  81 
  82     // Fully qualified name of class in this package -> fully qualified name of dependency
  83     private Map<String, Set<String>> dependencies = new TreeMap<>();
  84     // Fully qualified name of class in this package -> fully qualified name of dependency on class path
  85     private Map<String, Set<String>> cpDependencies = new TreeMap<>();
  86 
  87     // This is the public api of this package.
  88     private PubApi pubApi = new PubApi();
  89     // Map from source file name to Source info object.
  90     private Map<String,Source> sources = new HashMap<>();
  91     // This package generated these artifacts.
  92     private Map<String,File> artifacts = new HashMap<>();
  93 
  94     public Package(Module m, String n) {
  95         int c = n.indexOf(":");
  96         Assert.check(c != -1);

  97         Assert.check(m.name().equals(m.name()));
  98         name = n;
  99         dirname = n.replace('.', File.separatorChar);
 100         if (m.name().length() > 0) {
 101             // There is a module here, prefix the module dir name to the path.
 102             dirname = m.dirname()+File.separatorChar+dirname;
 103         }
 104     }
 105 
 106     public Module mod() { return mod; }
 107     public String name() { return name; }
 108     public String dirname() { return dirname; }
 109     public Map<String,Source> sources() { return sources; }
 110     public Map<String,File> artifacts() { return artifacts; }
 111     public PubApi getPubApi() { return pubApi; }
 112 
 113     public Map<String,Set<String>> typeDependencies() { return dependencies; }
 114     public Map<String,Set<String>> typeClasspathDependencies() { return cpDependencies; }
 115 

 116     public Set<String> dependents() { return dependents; }
 117 
 118     @Override
 119     public boolean equals(Object o) {
 120         return (o instanceof Package) && name.equals(((Package)o).name);
 121     }
 122 
 123     @Override
 124     public int hashCode() {
 125         return name.hashCode();
 126     }
 127 
 128     @Override
 129     public int compareTo(Package o) {
 130         return name.compareTo(o.name);
 131     }
 132 
 133     public void addSource(Source s) {
 134         sources.put(s.file().getPath(), s);
 135     }
 136 
 137     private static Pattern DEP_PATTERN = Pattern.compile("(.*) -> (.*)");
 138     public void parseAndAddDependency(String d, boolean cp) {
 139         Matcher m = DEP_PATTERN.matcher(d);
 140         if (!m.matches())
 141             throw new IllegalArgumentException("Bad dependency string: " + d);
 142         addDependency(m.group(1), m.group(2), cp);
 143     }
 144 
 145     public void addDependency(String fullyQualifiedFrom,
 146                               String fullyQualifiedTo,
 147                               boolean cp) {
 148         Map<String, Set<String>> map = cp ? cpDependencies : dependencies;
 149         if (!map.containsKey(fullyQualifiedFrom))
 150             map.put(fullyQualifiedFrom, new HashSet<>());
 151         map.get(fullyQualifiedFrom).add(fullyQualifiedTo);
 152     }
 153 
 154     public void addDependent(String d) {
 155         dependents.add(d);
 156     }
 157 
 158     /**
 159      * Check if we have knowledge in the javac state that
 160      * describe the results of compiling this package before.
 161      */
 162     public boolean existsInJavacState() {
 163         return artifacts.size() > 0 || !pubApi.isEmpty();
 164     }
 165 
 166     public boolean hasPubApiChanged(PubApi newPubApi) {
 167         return !newPubApi.isBackwardCompatibleWith(pubApi);






 168     }
 169 
 170     public void setPubapi(PubApi newPubApi) {
 171         pubApi = newPubApi;
























 172     }
 173 
 174     public void setDependencies(Map<String, Set<String>> ds, boolean cp) {
 175         (cp ? cpDependencies : dependencies).clear();
 176         for (String fullyQualifiedFrom : ds.keySet())
 177             for (String fullyQualifiedTo : ds.get(fullyQualifiedFrom))
 178                 addDependency(fullyQualifiedFrom, fullyQualifiedTo, cp);

 179     }
 180 
 181     public void save(StringBuilder b) {
 182         b.append("P ").append(name).append("\n");
 183         Source.saveSources(sources, b);
 184         saveDependencies(b);
 185         savePubapi(b);
 186         saveArtifacts(b);
 187     }
 188 
 189     static public Package load(Module module, String l) {
 190         String name = l.substring(2);
 191         return new Package(module, name);
 192     }
 193 
 194     public void saveDependencies(StringBuilder b) {



 195 
 196         // Dependencies where *to* is among sources
 197         for (String fullyQualifiedFrom : dependencies.keySet()) {
 198             for (String fullyQualifiedTo : dependencies.get(fullyQualifiedFrom)) {
 199                 b.append(String.format("D S %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
 200             }
 201         }
 202 
 203         // Dependencies where *to* is on class path
 204         for (String fullyQualifiedFrom : cpDependencies.keySet()) {
 205             for (String fullyQualifiedTo : cpDependencies.get(fullyQualifiedFrom)) {
 206                 b.append(String.format("D C %s -> %s%n", fullyQualifiedFrom, fullyQualifiedTo));
 207             }



 208         }
 209     }
 210 
 211     public void savePubapi(StringBuilder b) {
 212         pubApi.asListOfStrings()
 213               .stream()
 214               .flatMap(l -> Stream.of("I ", l, "\n"))
 215               .forEach(b::append);
 216     }
 217 
 218     public static void savePackages(Map<String,Package> packages, StringBuilder b) {
 219         List<String> sorted_packages = new ArrayList<>();
 220         for (String key : packages.keySet() ) {
 221             sorted_packages.add(key);
 222         }
 223         Collections.sort(sorted_packages);
 224         for (String s : sorted_packages) {
 225             Package p = packages.get(s);
 226             p.save(b);
 227         }
 228     }
 229 
 230     public void addArtifact(String a) {
 231         artifacts.put(a, new File(a));
 232     }
 233 
 234     public void addArtifact(File f) {
 235         artifacts.put(f.getPath(), f);