langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java
changeset 21046 ebf16a1a6328
parent 16550 f20e2521f3df
child 21503 45fc62482cae
equal deleted inserted replaced
21045:a7a1562c97be 21046:ebf16a1a6328
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 package com.sun.tools.jdeps;
    25 package com.sun.tools.jdeps;
    26 
    26 
    27 import com.sun.tools.classfile.Dependency.Location;
    27 import com.sun.tools.classfile.Dependency.Location;
    28 import java.util.ArrayList;
    28 import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
    29 import java.util.HashMap;
    29 import java.util.HashMap;
    30 import java.util.HashSet;
       
    31 import java.util.List;
    30 import java.util.List;
    32 import java.util.Map;
    31 import java.util.Map;
    33 import java.util.Set;
    32 import java.util.Set;
    34 import java.util.SortedMap;
    33 import java.util.SortedMap;
    35 import java.util.SortedSet;
    34 import java.util.SortedSet;
    50         CLASS,
    49         CLASS,
    51         VERBOSE
    50         VERBOSE
    52     };
    51     };
    53 
    52 
    54     private final Type type;
    53     private final Type type;
    55     private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>();
    54     private final Map<Archive, ArchiveDeps> results = new HashMap<>();
    56     private final Map<String, Archive> map = new HashMap<String, Archive>();
    55     private final Map<String, Archive> map = new HashMap<>();
    57     private final Archive NOT_FOUND
    56     private final Archive NOT_FOUND
    58         = new Archive(JdepsTask.getMessage("artifact.not.found"));
    57         = new Archive(JdepsTask.getMessage("artifact.not.found"));
    59 
    58 
    60     /**
    59     /**
    61      * Constructs an Analyzer instance.
    60      * Constructs an Analyzer instance.
    76                 deps = new ClassVisitor(archive);
    75                 deps = new ClassVisitor(archive);
    77             } else {
    76             } else {
    78                 deps = new PackageVisitor(archive);
    77                 deps = new PackageVisitor(archive);
    79             }
    78             }
    80             archive.visit(deps);
    79             archive.visit(deps);
    81             results.add(deps);
    80             results.put(archive, deps);
    82         }
    81         }
    83 
    82 
    84         // set the required dependencies
    83         // set the required dependencies
    85         for (ArchiveDeps result: results) {
    84         for (ArchiveDeps result: results.values()) {
    86             for (Set<String> set : result.deps.values()) {
    85             for (Set<String> set : result.deps.values()) {
    87                 for (String target : set) {
    86                 for (String target : set) {
    88                     Archive source = getArchive(target);
    87                     Archive source = getArchive(target);
    89                     if (result.archive != source) {
    88                     if (result.archive != source) {
    90                         if (!result.requiredArchives.contains(source)) {
    89                         String profile = "";
    91                             result.requiredArchives.add(source);
    90                         if (source instanceof JDKArchive) {
       
    91                             profile = result.profile != null ? result.profile.toString() : "";
       
    92                             if (result.getTargetProfile(target) == null) {
       
    93                                 profile += ", JDK internal API";
       
    94                                 // override the value if it accesses any JDK internal
       
    95                                 result.requireArchives.put(source, profile);
       
    96                                 continue;
       
    97                             }
    92                         }
    98                         }
    93                         // either a profile name or the archive name
    99                         if (!result.requireArchives.containsKey(source)) {
    94                         String tname = result.getTargetProfile(target);
   100                             result.requireArchives.put(source, profile);
    95                         if (tname.isEmpty()) {
       
    96                             tname = PlatformClassPath.contains(source)
       
    97                                         ? "JDK internal API (" + source.getFileName() + ")"
       
    98                                         : source.toString();
       
    99                         }
       
   100                         if (!result.targetNames.contains(tname)) {
       
   101                             result.targetNames.add(tname);
       
   102                         }
   101                         }
   103                     }
   102                     }
   104                 }
   103                 }
   105             }
   104             }
   106         }
   105         }
   107     }
   106     }
   108 
   107 
       
   108     public boolean hasDependences(Archive archive) {
       
   109         if (results.containsKey(archive)) {
       
   110             return results.get(archive).deps.size() > 0;
       
   111         }
       
   112         return false;
       
   113     }
       
   114 
   109     public interface Visitor {
   115     public interface Visitor {
       
   116         /**
       
   117          * Visits the source archive to its destination archive of
       
   118          * a recorded dependency.
       
   119          */
       
   120         void visitArchiveDependence(Archive origin, Archive target, String profile);
   110         /**
   121         /**
   111          * Visits a recorded dependency from origin to target which can be
   122          * Visits a recorded dependency from origin to target which can be
   112          * a fully-qualified classname, a package name, a profile or
   123          * a fully-qualified classname, a package name, a profile or
   113          * archive name depending on the Analyzer's type.
   124          * archive name depending on the Analyzer's type.
   114          */
   125          */
   115         void visit(String origin, String target, String profile);
   126         void visitDependence(String origin, Archive source, String target, Archive archive, String profile);
   116         /**
   127     }
   117          * Visits the source archive to its destination archive of
   128 
   118          * a recorded dependency.
   129     public void visitArchiveDependences(Archive source, Visitor v) {
   119          */
   130         ArchiveDeps r = results.get(source);
   120         void visit(Archive source, Archive dest);
   131         for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
   121     }
   132             v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
   122 
   133         }
   123     public void visitSummary(Visitor v) {
   134     }
   124         for (ArchiveDeps r : results) {
   135 
   125             for (Archive a : r.requiredArchives) {
   136     public void visitDependences(Archive source, Visitor v) {
   126                 v.visit(r.archive, a);
   137         ArchiveDeps r = results.get(source);
   127             }
   138         for (String origin : r.deps.keySet()) {
   128             for (String name : r.targetNames) {
   139             for (String target : r.deps.get(origin)) {
   129                 v.visit(r.archive.getFileName(), name, name);
   140                 Archive archive = getArchive(target);
   130             }
   141                 assert source == getArchive(origin);
   131         }
   142                 Profile profile = r.getTargetProfile(target);
   132     }
   143 
   133 
   144                 // filter intra-dependency unless in verbose mode
   134     public void visit(Visitor v) {
   145                 if (type == Type.VERBOSE || archive != source) {
   135         for (ArchiveDeps r: results) {
   146                     v.visitDependence(origin, source, target, archive,
   136             for (Archive a : r.requiredArchives) {
   147                                       profile != null ? profile.toString() : "");
   137                 v.visit(r.archive, a);
       
   138             }
       
   139             for (String origin : r.deps.keySet()) {
       
   140                 for (String target : r.deps.get(origin)) {
       
   141                     // filter intra-dependency unless in verbose mode
       
   142                     if (type == Type.VERBOSE || getArchive(origin) != getArchive(target)) {
       
   143                         v.visit(origin, target, r.getTargetProfile(target));
       
   144                     }
       
   145                 }
   148                 }
   146             }
   149             }
   147         }
   150         }
   148     }
   151     }
   149 
   152 
   150     public Archive getArchive(String name) {
   153     public Archive getArchive(String name) {
   151         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
   154         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
   152     }
   155     }
   153 
   156 
   154     /**
       
   155      * Returns the file name of the archive for non-JRE class or
       
   156      * internal JRE classes.  It returns empty string for SE API.
       
   157      */
       
   158     public String getArchiveName(String target, String profile) {
       
   159         Archive source = getArchive(target);
       
   160         String name = source.getFileName();
       
   161         if (PlatformClassPath.contains(source))
       
   162             return profile.isEmpty() ? "JDK internal API (" + name + ")" : "";
       
   163         return name;
       
   164     }
       
   165 
       
   166     private abstract class ArchiveDeps implements Archive.Visitor {
   157     private abstract class ArchiveDeps implements Archive.Visitor {
   167         final Archive archive;
   158         final Archive archive;
   168         final Set<Archive> requiredArchives;
   159         final Map<Archive,String> requireArchives;
   169         final SortedSet<String> targetNames;
       
   170         final SortedMap<String, SortedSet<String>> deps;
   160         final SortedMap<String, SortedSet<String>> deps;
   171 
   161         Profile profile = null;
   172         ArchiveDeps(Archive archive) {
   162         ArchiveDeps(Archive archive) {
   173             this.archive = archive;
   163             this.archive = archive;
   174             this.requiredArchives = new HashSet<Archive>();
   164             this.requireArchives = new HashMap<>();
   175             this.targetNames = new TreeSet<String>();
   165             this.deps = new TreeMap<>();
   176             this.deps = new TreeMap<String, SortedSet<String>>();
       
   177         }
   166         }
   178 
   167 
   179         void add(String loc) {
   168         void add(String loc) {
   180             Archive a = map.get(loc);
   169             Archive a = map.get(loc);
   181             if (a == null) {
   170             if (a == null) {
   186         }
   175         }
   187 
   176 
   188         void add(String origin, String target) {
   177         void add(String origin, String target) {
   189             SortedSet<String> set = deps.get(origin);
   178             SortedSet<String> set = deps.get(origin);
   190             if (set == null) {
   179             if (set == null) {
   191                 set = new TreeSet<String>();
   180                 deps.put(origin, set = new TreeSet<>());
   192                 deps.put(origin, set);
       
   193             }
   181             }
   194             if (!set.contains(target)) {
   182             if (!set.contains(target)) {
   195                 set.add(target);
   183                 set.add(target);
   196             }
   184                 // find the corresponding profile
   197         }
   185                 Profile p = getTargetProfile(target);
   198 
   186                 if (profile == null || (p != null && profile.profile < p.profile)) {
       
   187                      profile = p;
       
   188                 }
       
   189             }
       
   190         }
   199         public abstract void visit(Location o, Location t);
   191         public abstract void visit(Location o, Location t);
   200         public abstract String getTargetProfile(String target);
   192         public abstract Profile getTargetProfile(String target);
   201 
       
   202     }
   193     }
   203 
   194 
   204     private class ClassVisitor extends ArchiveDeps {
   195     private class ClassVisitor extends ArchiveDeps {
   205         ClassVisitor(Archive archive) {
   196         ClassVisitor(Archive archive) {
   206             super(archive);
   197             super(archive);
   209             add(l.getClassName());
   200             add(l.getClassName());
   210         }
   201         }
   211         public void visit(Location o, Location t) {
   202         public void visit(Location o, Location t) {
   212             add(o.getClassName(), t.getClassName());
   203             add(o.getClassName(), t.getClassName());
   213         }
   204         }
   214         public String getTargetProfile(String target) {
   205         public Profile getTargetProfile(String target) {
   215             int i = target.lastIndexOf('.');
   206             int i = target.lastIndexOf('.');
   216             return (i > 0) ? Profiles.getProfileName(target.substring(0, i)) : "";
   207             return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
   217         }
   208         }
   218     }
   209     }
   219 
   210 
   220     private class PackageVisitor extends ArchiveDeps {
   211     private class PackageVisitor extends ArchiveDeps {
   221         PackageVisitor(Archive archive) {
   212         PackageVisitor(Archive archive) {
   229         }
   220         }
   230         private String packageOf(Location loc) {
   221         private String packageOf(Location loc) {
   231             String pkg = loc.getPackageName();
   222             String pkg = loc.getPackageName();
   232             return pkg.isEmpty() ? "<unnamed>" : pkg;
   223             return pkg.isEmpty() ? "<unnamed>" : pkg;
   233         }
   224         }
   234         public String getTargetProfile(String target) {
   225         public Profile getTargetProfile(String target) {
   235             return Profiles.getProfileName(target);
   226             return Profile.getProfile(target);
   236         }
   227         }
   237     }
   228     }
   238 }
   229 }