src/share/classes/com/sun/tools/jdeps/Analyzer.java

Print this page




   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 package com.sun.tools.jdeps;
  26 
  27 import com.sun.tools.classfile.Dependency.Location;
  28 import java.util.ArrayList;
  29 import java.util.HashMap;
  30 import java.util.HashSet;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.Set;
  34 import java.util.SortedMap;
  35 import java.util.SortedSet;
  36 import java.util.TreeMap;
  37 import java.util.TreeSet;
  38 
  39 /**
  40  * Dependency Analyzer.
  41  */
  42 public class Analyzer {
  43     /**
  44      * Type of the dependency analysis.  Appropriate level of data
  45      * will be stored.
  46      */
  47     public enum Type {
  48         SUMMARY,
  49         PACKAGE,
  50         CLASS,
  51         VERBOSE
  52     };
  53 
  54     private final Type type;
  55     private final List<ArchiveDeps> results = new ArrayList<ArchiveDeps>();
  56     private final Map<String, Archive> map = new HashMap<String, Archive>();
  57     private final Archive NOT_FOUND
  58         = new Archive(JdepsTask.getMessage("artifact.not.found"));
  59 
  60     /**
  61      * Constructs an Analyzer instance.
  62      *
  63      * @param type Type of the dependency analysis
  64      */
  65     public Analyzer(Type type) {
  66         this.type = type;
  67     }
  68 
  69     /**
  70      * Performs the dependency analysis on the given archives.
  71      */
  72     public void run(List<Archive> archives) {
  73         for (Archive archive : archives) {
  74             ArchiveDeps deps;
  75             if (type == Type.CLASS || type == Type.VERBOSE) {
  76                 deps = new ClassVisitor(archive);
  77             } else {
  78                 deps = new PackageVisitor(archive);
  79             }
  80             archive.visit(deps);
  81             results.add(deps);
  82         }
  83 
  84         // set the required dependencies
  85         for (ArchiveDeps result: results) {
  86             for (Set<String> set : result.deps.values()) {
  87                 for (String target : set) {
  88                     Archive source = getArchive(target);
  89                     if (result.archive != source) {
  90                         if (!result.requiredArchives.contains(source)) {
  91                             result.requiredArchives.add(source);






  92                         }
  93                         // either a profile name or the archive name
  94                         String tname = result.getTargetProfile(target);
  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                         }
 103                     }
 104                 }
 105             }
 106         }
 107     }
 108 







 109     public interface Visitor {
 110         /**





 111          * Visits a recorded dependency from origin to target which can be
 112          * a fully-qualified classname, a package name, a profile or
 113          * archive name depending on the Analyzer's type.
 114          */
 115         void visit(String origin, String target, String profile);
 116         /**
 117          * Visits the source archive to its destination archive of
 118          * a recorded dependency.
 119          */
 120         void visit(Archive source, Archive dest);
 121     }
 122 
 123     public void visitSummary(Visitor v) {
 124         for (ArchiveDeps r : results) {
 125             for (Archive a : r.requiredArchives) {
 126                 v.visit(r.archive, a);
 127             }
 128             for (String name : r.targetNames) {
 129                 v.visit(r.archive.getFileName(), name, name);
 130             }
 131         }
 132     }
 133 
 134     public void visit(Visitor v) {
 135         for (ArchiveDeps r: results) {
 136             for (Archive a : r.requiredArchives) {
 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                 }
 146             }
 147         }
 148     }
 149 
 150     public Archive getArchive(String name) {
 151         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
 152     }
 153 
 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 {
 167         final Archive archive;
 168         final Set<Archive> requiredArchives;
 169         final SortedSet<String> targetNames;
 170         final SortedMap<String, SortedSet<String>> deps;
 171 
 172         ArchiveDeps(Archive archive) {
 173             this.archive = archive;
 174             this.requiredArchives = new HashSet<Archive>();
 175             this.targetNames = new TreeSet<String>();
 176             this.deps = new TreeMap<String, SortedSet<String>>();
 177         }
 178 
 179         void add(String loc) {
 180             Archive a = map.get(loc);
 181             if (a == null) {
 182                 map.put(loc, archive);
 183             } else if (a != archive) {
 184                 // duplicated class warning?
 185             }
 186         }
 187 
 188         void add(String origin, String target) {
 189             SortedSet<String> set = deps.get(origin);
 190             if (set == null) {
 191                 set = new TreeSet<String>();
 192                 deps.put(origin, set);
 193             }
 194             if (!set.contains(target)) {
 195                 set.add(target);





 196             }
 197         }
 198 
 199         public abstract void visit(Location o, Location t);
 200         public abstract String getTargetProfile(String target);
 201 
 202     }
 203 
 204     private class ClassVisitor extends ArchiveDeps {
 205         ClassVisitor(Archive archive) {
 206             super(archive);
 207         }
 208         public void visit(Location l) {
 209             add(l.getClassName());
 210         }
 211         public void visit(Location o, Location t) {
 212             add(o.getClassName(), t.getClassName());
 213         }
 214         public String getTargetProfile(String target) {
 215             int i = target.lastIndexOf('.');
 216             return (i > 0) ? Profiles.getProfileName(target.substring(0, i)) : "";
 217         }
 218     }
 219 
 220     private class PackageVisitor extends ArchiveDeps {
 221         PackageVisitor(Archive archive) {
 222             super(archive);
 223         }
 224         public void visit(Location o, Location t) {
 225             add(packageOf(o), packageOf(t));
 226         }
 227         public void visit(Location l) {
 228             add(packageOf(l));
 229         }
 230         private String packageOf(Location loc) {
 231             String pkg = loc.getPackageName();
 232             return pkg.isEmpty() ? "<unnamed>" : pkg;
 233         }
 234         public String getTargetProfile(String target) {
 235             return Profiles.getProfileName(target);
 236         }
 237     }
 238 }


   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 package com.sun.tools.jdeps;
  26 
  27 import com.sun.tools.classfile.Dependency.Location;
  28 import com.sun.tools.jdeps.Profile;
  29 import java.util.HashMap;
  30 import java.util.LinkedHashMap;
  31 import java.util.List;
  32 import java.util.Map;
  33 import java.util.Set;
  34 import java.util.SortedMap;
  35 import java.util.SortedSet;
  36 import java.util.TreeMap;
  37 import java.util.TreeSet;
  38 
  39 /**
  40  * Dependency Analyzer.
  41  */
  42 public class Analyzer {
  43     /**
  44      * Type of the dependency analysis.  Appropriate level of data
  45      * will be stored.
  46      */
  47     public enum Type {
  48         SUMMARY,
  49         PACKAGE,
  50         CLASS,
  51         VERBOSE
  52     };
  53 
  54     private final Type type;
  55     private final Map<Archive, ArchiveDeps> results = new LinkedHashMap<>();
  56     private final Map<String, Archive> map = new HashMap<>();
  57     private final Archive NOT_FOUND
  58         = new Archive(JdepsTask.getMessage("artifact.not.found"));
  59 
  60     /**
  61      * Constructs an Analyzer instance.
  62      *
  63      * @param type Type of the dependency analysis
  64      */
  65     public Analyzer(Type type) {
  66         this.type = type;
  67     }
  68 
  69     /**
  70      * Performs the dependency analysis on the given archives.
  71      */
  72     public void run(List<Archive> archives) {
  73         for (Archive archive : archives) {
  74             ArchiveDeps deps;
  75             if (type == Type.CLASS || type == Type.VERBOSE) {
  76                 deps = new ClassVisitor(archive);
  77             } else {
  78                 deps = new PackageVisitor(archive);
  79             }
  80             archive.visit(deps);
  81             results.put(archive, deps);
  82         }
  83 
  84         // set the required dependencies
  85         for (ArchiveDeps result: results.values()) {
  86             for (Set<String> set : result.deps.values()) {
  87                 for (String target : set) {
  88                     Archive source = getArchive(target);
  89                     if (result.archive != source) {
  90                         String profile = "";
  91                         if (PlatformClassPath.contains(source)) {
  92                             profile = result.profile != null ? result.profile.toString() : "";
  93                             if (result.getTargetProfile(target) == null) {
  94                                 profile += ", JDK internal API";
  95                                 // override the value if it accesses any JDK internal
  96                                 result.requireArchives.put(source, profile);
  97                                 continue;
  98                             }






  99                         }
 100                         if (!result.requireArchives.containsKey(source)) {
 101                             result.requireArchives.put(source, profile);
 102                         }
 103                     }
 104                 }
 105             }
 106         }
 107     }
 108 
 109     public boolean hasDependences(Archive archive) {
 110         if (results.containsKey(archive)) {
 111             return results.get(archive).deps.size() > 0;
 112         }
 113         return false;
 114     }
 115 
 116     public interface Visitor {
 117         /**
 118          * Visits the source archive to its destination archive of
 119          * a recorded dependency.
 120          */
 121         void visitArchiveDependence(Archive origin, Archive target, String profile);
 122         /**
 123          * Visits a recorded dependency from origin to target which can be
 124          * a fully-qualified classname, a package name, a profile or
 125          * archive name depending on the Analyzer's type.
 126          */
 127         void visitDependence(String origin, Archive source, String target, Archive archive, String profile);





 128     }
 129 
 130     public void visitArchiveDependences(Archive source, Visitor v) {
 131         ArchiveDeps r = results.get(source);
 132         for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
 133             v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());




 134         }
 135     }
 136 
 137     public void visitDependences(Archive source, Visitor v) {
 138         ArchiveDeps r = results.get(source);



 139         for (String origin : r.deps.keySet()) {
 140             for (String target : r.deps.get(origin)) {
 141                 Archive archive = getArchive(target);
 142                 assert source == getArchive(origin);
 143                 Profile profile = r.getTargetProfile(target);
 144 
 145                 // filter intra-dependency unless in verbose mode
 146                 if (type == Type.VERBOSE || archive != source) {
 147                     v.visitDependence(origin, source, target, archive,
 148                                       profile != null ? profile.toString() : "");
 149                 }
 150             }
 151         }
 152     }
 153 
 154     public Archive getArchive(String name) {
 155         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
 156     }
 157 












 158     private abstract class ArchiveDeps implements Archive.Visitor {
 159         final Archive archive;
 160         final Map<Archive,String> requireArchives;

 161         final SortedMap<String, SortedSet<String>> deps;
 162         Profile profile = null;
 163         ArchiveDeps(Archive archive) {
 164             this.archive = archive;
 165             this.requireArchives = new HashMap<>();
 166             this.deps = new TreeMap<>();

 167         }
 168 
 169         void add(String loc) {
 170             Archive a = map.get(loc);
 171             if (a == null) {
 172                 map.put(loc, archive);
 173             } else if (a != archive) {
 174                 // duplicated class warning?
 175             }
 176         }
 177 
 178         void add(String origin, String target) {
 179             SortedSet<String> set = deps.get(origin);
 180             if (set == null) {
 181                 deps.put(origin, set = new TreeSet<>());

 182             }
 183             if (!set.contains(target)) {
 184                 set.add(target);
 185                 // find the corresponding profile
 186                 Profile p = getTargetProfile(target);
 187                 if (profile == null || (p != null && profile.profile < p.profile)) {
 188                      profile = p;
 189                 }
 190             }
 191         }

 192         public abstract void visit(Location o, Location t);
 193         public abstract Profile getTargetProfile(String target);

 194     }
 195 
 196     private class ClassVisitor extends ArchiveDeps {
 197         ClassVisitor(Archive archive) {
 198             super(archive);
 199         }
 200         public void visit(Location l) {
 201             add(l.getClassName());
 202         }
 203         public void visit(Location o, Location t) {
 204             add(o.getClassName(), t.getClassName());
 205         }
 206         public Profile getTargetProfile(String target) {
 207             int i = target.lastIndexOf('.');
 208             return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
 209         }
 210     }
 211 
 212     private class PackageVisitor extends ArchiveDeps {
 213         PackageVisitor(Archive archive) {
 214             super(archive);
 215         }
 216         public void visit(Location o, Location t) {
 217             add(packageOf(o), packageOf(t));
 218         }
 219         public void visit(Location l) {
 220             add(packageOf(l));
 221         }
 222         private String packageOf(Location loc) {
 223             String pkg = loc.getPackageName();
 224             return pkg.isEmpty() ? "<unnamed>" : pkg;
 225         }
 226         public Profile getTargetProfile(String target) {
 227             return Profile.getProfile(target);
 228         }
 229     }
 230 }