langtools/src/share/classes/com/sun/tools/sjavac/Package.java
changeset 15368 2577ddb7e710
child 22448 a85fbad9d687
child 22163 3651128c74eb
equal deleted inserted replaced
15367:31b57f2b8d0b 15368:2577ddb7e710
       
     1 /*
       
     2  * Copyright (c) 2012, 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 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 
       
    39 /**
       
    40  * The Package class maintains meta information about a package.
       
    41  * For example its sources, dependents,its pubapi and its artifacts.
       
    42  *
       
    43  * It might look odd that we track dependents/pubapi/artifacts on
       
    44  * a package level, but it makes sense since recompiling a full package
       
    45  * takes as long as recompiling a single java file in that package,
       
    46  * if you take into account the startup time of the jvm.
       
    47  *
       
    48  * Also the dependency information will be much smaller (good for the javac_state file size)
       
    49  * and it simplifies tracking artifact generation, you do not always know from which
       
    50  * source a class file was generated, but you always know which package it belongs to.
       
    51  *
       
    52  * It is also educational to see package dependencies triggering recompilation of
       
    53  * other packages. Even though the recompilation was perhaps not necessary,
       
    54  * the visible recompilation of the dependent packages indicates how much circular
       
    55  * dependencies your code has.
       
    56  *
       
    57  * <p><b>This is NOT part of any supported API.
       
    58  * If you write code that depends on this, you do so at your own
       
    59  * risk.  This code and its internal interfaces are subject to change
       
    60  * or deletion without notice.</b></p>
       
    61  */
       
    62 public class Package implements Comparable<Package> {
       
    63     // The module this package belongs to. (There is a legacy module with an empty string name,
       
    64     // used for all legacy sources.)
       
    65     private Module mod;
       
    66     // Name of this package, module:pkg
       
    67     // ex1 jdk.base:java.lang
       
    68     // ex2 :java.lang (when in legacy mode)
       
    69     private String name;
       
    70     // The directory path to the package. If the package belongs to a module,
       
    71     // then that module's file system name is part of the path.
       
    72     private String dirname;
       
    73     // This package depends on these packages.
       
    74     private Set<String> dependencies = new HashSet<String>();
       
    75     // This package has the following dependents, that depend on this package.
       
    76     private Set<String> dependents = new HashSet<String>();
       
    77     // This is the public api of this package.
       
    78     private List<String> pubapi = new ArrayList<String>();
       
    79     // Map from source file name to Source info object.
       
    80     private Map<String,Source> sources = new HashMap<String,Source>();
       
    81     // This package generated these artifacts.
       
    82     private Map<String,File> artifacts = new HashMap<String,File>();
       
    83 
       
    84     public Package(Module m, String n) {
       
    85         int c = n.indexOf(":");
       
    86         assert(c != -1);
       
    87         String mn = n.substring(0,c);
       
    88         assert(m.name().equals(m.name()));
       
    89         name = n;
       
    90         dirname = n.replace('.', File.separatorChar);
       
    91         if (m.name().length() > 0) {
       
    92             // There is a module here, prefix the module dir name to the path.
       
    93             dirname = m.dirname()+File.separatorChar+dirname;
       
    94         }
       
    95     }
       
    96 
       
    97     public Module mod() { return mod; }
       
    98     public String name() { return name; }
       
    99     public String dirname() { return dirname; }
       
   100     public Map<String,Source> sources() { return sources; }
       
   101     public Map<String,File> artifacts() { return artifacts; }
       
   102     public List<String> pubapi() { return pubapi; }
       
   103 
       
   104     public Set<String> dependencies() { return dependencies; }
       
   105     public Set<String> dependents() { return dependents; }
       
   106 
       
   107     @Override
       
   108     public boolean equals(Object o) {
       
   109         return (o instanceof Package) && name.equals(((Package)o).name);
       
   110     }
       
   111 
       
   112     @Override
       
   113     public int hashCode() {
       
   114         return name.hashCode();
       
   115     }
       
   116 
       
   117     @Override
       
   118     public int compareTo(Package o) {
       
   119         return name.compareTo(o.name);
       
   120     }
       
   121 
       
   122     public void addSource(Source s) {
       
   123         sources.put(s.file().getPath(), s);
       
   124     }
       
   125 
       
   126     public void addDependency(String d) {
       
   127         dependencies.add(d);
       
   128     }
       
   129 
       
   130     public void addDependent(String d) {
       
   131         dependents.add(d);
       
   132     }
       
   133 
       
   134     public void addPubapi(String p) {
       
   135         pubapi.add(p);
       
   136     }
       
   137 
       
   138     /**
       
   139      * Check if we have knowledge in the javac state that
       
   140      * describe the results of compiling this package before.
       
   141      */
       
   142     public boolean existsInJavacState() {
       
   143         return artifacts.size() > 0 || pubapi.size() > 0;
       
   144     }
       
   145 
       
   146     public static List<String> pubapiToList(String ps)
       
   147     {
       
   148         String[] lines = ps.split("\n");
       
   149         List<String> r = new ArrayList<String>();
       
   150         for (String l : lines) {
       
   151             r.add(l);
       
   152         }
       
   153         return r;
       
   154     }
       
   155 
       
   156     public boolean hasPubapiChanged(List<String> ps) {
       
   157         Iterator<String> i = ps.iterator();
       
   158         Iterator<String> j = pubapi.iterator();
       
   159         int line = 0;
       
   160         while (i.hasNext() && j.hasNext()) {
       
   161             String is = i.next();
       
   162             String js = j.next();
       
   163             if (!is.equals(js)) {
       
   164                 Log.debug("Change in pubapi for package "+name+" line "+line);
       
   165                 Log.debug("Old: "+js);
       
   166                 Log.debug("New: "+is);
       
   167                 return true;
       
   168             }
       
   169             line++;
       
   170         }
       
   171         if ((i.hasNext() && !j.hasNext() ) ||
       
   172             (!i.hasNext() && j.hasNext())) {
       
   173             Log.debug("Change in pubapi for package "+name);
       
   174             if (i.hasNext()) {
       
   175                 Log.debug("New has more lines!");
       
   176             } else {
       
   177                 Log.debug("Old has more lines!");
       
   178             }
       
   179             return true;
       
   180         }
       
   181         return false;
       
   182     }
       
   183 
       
   184     public void setPubapi(List<String> ps) {
       
   185         pubapi = ps;
       
   186     }
       
   187 
       
   188     public void setDependencies(Set<String> ds) {
       
   189         dependencies = ds;
       
   190     }
       
   191 
       
   192     public void save(StringBuilder b) {
       
   193         b.append("P ").append(name).append("\n");
       
   194         Source.saveSources(sources, b);
       
   195         saveDependencies(b);
       
   196         savePubapi(b);
       
   197         saveArtifacts(b);
       
   198     }
       
   199 
       
   200     static public Package load(Module module, String l) {
       
   201         String name = l.substring(2);
       
   202         return new Package(module, name);
       
   203     }
       
   204 
       
   205     public void loadDependency(String l) {
       
   206         String n = l.substring(2);
       
   207         addDependency(n);
       
   208     }
       
   209 
       
   210     public void loadPubapi(String l) {
       
   211         String pi = l.substring(2);
       
   212         addPubapi(pi);
       
   213     }
       
   214 
       
   215     public void saveDependencies(StringBuilder b) {
       
   216         List<String> sorted_dependencies = new ArrayList<String>();
       
   217         for (String key : dependencies) {
       
   218             sorted_dependencies.add(key);
       
   219         }
       
   220         Collections.sort(sorted_dependencies);
       
   221         for (String a : sorted_dependencies) {
       
   222             b.append("D "+a+"\n");
       
   223         }
       
   224     }
       
   225 
       
   226     public void savePubapi(StringBuilder b) {
       
   227         for (String l : pubapi) {
       
   228             b.append("I "+l+"\n");
       
   229         }
       
   230     }
       
   231 
       
   232     public static void savePackages(Map<String,Package> packages, StringBuilder b) {
       
   233         List<String> sorted_packages = new ArrayList<String>();
       
   234         for (String key : packages.keySet() ) {
       
   235             sorted_packages.add(key);
       
   236         }
       
   237         Collections.sort(sorted_packages);
       
   238         for (String s : sorted_packages) {
       
   239             Package p = packages.get(s);
       
   240             p.save(b);
       
   241         }
       
   242     }
       
   243 
       
   244     public void addArtifact(String a) {
       
   245         artifacts.put(a, new File(a));
       
   246     }
       
   247 
       
   248     public void addArtifact(File f) {
       
   249         artifacts.put(f.getPath(), f);
       
   250     }
       
   251 
       
   252     public void addArtifacts(Set<URI> as) {
       
   253         for (URI u : as) {
       
   254             addArtifact(new File(u));
       
   255         }
       
   256     }
       
   257 
       
   258     public void setArtifacts(Set<URI> as) {
       
   259         assert(!artifacts.isEmpty());
       
   260         artifacts = new HashMap<String,File>();
       
   261         addArtifacts(as);
       
   262     }
       
   263 
       
   264     public void loadArtifact(String l) {
       
   265         // Find next space after "A ".
       
   266         int dp = l.indexOf(' ',2);
       
   267         String fn = l.substring(2,dp);
       
   268         long last_modified = Long.parseLong(l.substring(dp+1));
       
   269         File f = new File(fn);
       
   270         if (f.exists() && f.lastModified() != last_modified) {
       
   271             // Hmm, the artifact on disk does not have the same last modified
       
   272             // timestamp as the information from the build database.
       
   273             // We no longer trust the artifact on disk. Delete it.
       
   274             // The smart javac wrapper will then rebuild the artifact.
       
   275             Log.debug("Removing "+f.getPath()+" since its timestamp does not match javac_state.");
       
   276             f.delete();
       
   277         }
       
   278         artifacts.put(f.getPath(), f);
       
   279     }
       
   280 
       
   281     public void saveArtifacts(StringBuilder b) {
       
   282         List<File> sorted_artifacts = new ArrayList<File>();
       
   283         for (File f : artifacts.values()) {
       
   284             sorted_artifacts.add(f);
       
   285         }
       
   286         Collections.sort(sorted_artifacts);
       
   287         for (File f : sorted_artifacts) {
       
   288             // The last modified information is only used
       
   289             // to detect tampering with the output dir.
       
   290             // If the outputdir has been modified, not by javac,
       
   291             // then a mismatch will be detected in the last modified
       
   292             // timestamps stored in the build database compared
       
   293             // to the timestamps on disk and the artifact will be deleted.
       
   294 
       
   295             b.append("A "+f.getPath()+" "+f.lastModified()+"\n");
       
   296         }
       
   297     }
       
   298 
       
   299     /**
       
   300      * Always clean out a tainted package before it is recompiled.
       
   301      */
       
   302     public void deleteArtifacts() {
       
   303         for (File a : artifacts.values()) {
       
   304             a.delete();
       
   305         }
       
   306     }
       
   307 }