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

changeset 2172
aa91bc6e8480
parent 2139
defadd528513
child 2525
2eb010b6cb22
child 2538
1e39ae45d8ac
     1.1 --- a/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Mon Oct 28 12:29:34 2013 -0700
     1.2 +++ b/src/share/classes/com/sun/tools/jdeps/Analyzer.java	Wed Oct 30 08:35:52 2013 -0700
     1.3 @@ -26,9 +26,11 @@
     1.4  
     1.5  import com.sun.tools.classfile.Dependency.Location;
     1.6  import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
     1.7 +import java.util.ArrayList;
     1.8  import java.util.HashMap;
     1.9  import java.util.List;
    1.10  import java.util.Map;
    1.11 +import java.util.Objects;
    1.12  import java.util.Set;
    1.13  import java.util.SortedMap;
    1.14  import java.util.SortedSet;
    1.15 @@ -52,7 +54,7 @@
    1.16  
    1.17      private final Type type;
    1.18      private final Map<Archive, ArchiveDeps> results = new HashMap<>();
    1.19 -    private final Map<String, Archive> map = new HashMap<>();
    1.20 +    private final Map<Location, Archive> map = new HashMap<>();
    1.21      private final Archive NOT_FOUND
    1.22          = new Archive(JdepsTask.getMessage("artifact.not.found"));
    1.23  
    1.24 @@ -69,6 +71,17 @@
    1.25       * Performs the dependency analysis on the given archives.
    1.26       */
    1.27      public void run(List<Archive> archives) {
    1.28 +        // build a map from Location to Archive
    1.29 +        for (Archive archive: archives) {
    1.30 +            for (Location l: archive.getClasses()) {
    1.31 +                if (!map.containsKey(l)) {
    1.32 +                    map.put(l, archive);
    1.33 +                } else {
    1.34 +                    // duplicated class warning?
    1.35 +                }
    1.36 +            }
    1.37 +        }
    1.38 +        // traverse and analyze all dependencies
    1.39          for (Archive archive : archives) {
    1.40              ArchiveDeps deps;
    1.41              if (type == Type.CLASS || type == Type.VERBOSE) {
    1.42 @@ -76,33 +89,9 @@
    1.43              } else {
    1.44                  deps = new PackageVisitor(archive);
    1.45              }
    1.46 -            archive.visit(deps);
    1.47 +            archive.visitDependences(deps);
    1.48              results.put(archive, deps);
    1.49          }
    1.50 -
    1.51 -        // set the required dependencies
    1.52 -        for (ArchiveDeps result: results.values()) {
    1.53 -            for (Set<String> set : result.deps.values()) {
    1.54 -                for (String target : set) {
    1.55 -                    Archive source = getArchive(target);
    1.56 -                    if (result.archive != source) {
    1.57 -                        String profile = "";
    1.58 -                        if (source instanceof JDKArchive) {
    1.59 -                            profile = result.profile != null ? result.profile.toString() : "";
    1.60 -                            if (result.getTargetProfile(target) == null) {
    1.61 -                                profile += ", JDK internal API";
    1.62 -                                // override the value if it accesses any JDK internal
    1.63 -                                result.requireArchives.put(source, profile);
    1.64 -                                continue;
    1.65 -                            }
    1.66 -                        }
    1.67 -                        if (!result.requireArchives.containsKey(source)) {
    1.68 -                            result.requireArchives.put(source, profile);
    1.69 -                        }
    1.70 -                    }
    1.71 -                }
    1.72 -            }
    1.73 -        }
    1.74      }
    1.75  
    1.76      public boolean hasDependences(Archive archive) {
    1.77 @@ -117,94 +106,143 @@
    1.78           * Visits the source archive to its destination archive of
    1.79           * a recorded dependency.
    1.80           */
    1.81 -        void visitArchiveDependence(Archive origin, Archive target, String profile);
    1.82 +        void visitArchiveDependence(Archive origin, Archive target, Profile profile);
    1.83          /**
    1.84           * Visits a recorded dependency from origin to target which can be
    1.85           * a fully-qualified classname, a package name, a profile or
    1.86           * archive name depending on the Analyzer's type.
    1.87           */
    1.88 -        void visitDependence(String origin, Archive source, String target, Archive archive, String profile);
    1.89 +        void visitDependence(String origin, Archive source, String target, Archive archive, Profile profile);
    1.90      }
    1.91  
    1.92      public void visitArchiveDependences(Archive source, Visitor v) {
    1.93          ArchiveDeps r = results.get(source);
    1.94 -        for (Map.Entry<Archive,String> e : r.requireArchives.entrySet()) {
    1.95 -            v.visitArchiveDependence(r.archive, e.getKey(), e.getValue());
    1.96 +        for (ArchiveDeps.Dep d: r.requireArchives()) {
    1.97 +            v.visitArchiveDependence(r.archive, d.archive, d.profile);
    1.98          }
    1.99      }
   1.100  
   1.101      public void visitDependences(Archive source, Visitor v) {
   1.102          ArchiveDeps r = results.get(source);
   1.103 -        for (String origin : r.deps.keySet()) {
   1.104 -            for (String target : r.deps.get(origin)) {
   1.105 -                Archive archive = getArchive(target);
   1.106 -                assert source == getArchive(origin);
   1.107 -                Profile profile = r.getTargetProfile(target);
   1.108 -
   1.109 +        for (Map.Entry<String, SortedSet<ArchiveDeps.Dep>> e: r.deps.entrySet()) {
   1.110 +            String origin = e.getKey();
   1.111 +            for (ArchiveDeps.Dep d: e.getValue()) {
   1.112                  // filter intra-dependency unless in verbose mode
   1.113 -                if (type == Type.VERBOSE || archive != source) {
   1.114 -                    v.visitDependence(origin, source, target, archive,
   1.115 -                                      profile != null ? profile.toString() : "");
   1.116 +                if (type == Type.VERBOSE || d.archive != source) {
   1.117 +                    v.visitDependence(origin, source, d.target, d.archive, d.profile);
   1.118                  }
   1.119              }
   1.120          }
   1.121      }
   1.122  
   1.123 -    public Archive getArchive(String name) {
   1.124 -        return map.containsKey(name) ? map.get(name) : NOT_FOUND;
   1.125 -    }
   1.126 -
   1.127 +    /**
   1.128 +     * ArchiveDeps contains the dependencies for an Archive that
   1.129 +     * can have one or more classes.
   1.130 +     */
   1.131      private abstract class ArchiveDeps implements Archive.Visitor {
   1.132          final Archive archive;
   1.133 -        final Map<Archive,String> requireArchives;
   1.134 -        final SortedMap<String, SortedSet<String>> deps;
   1.135 -        Profile profile = null;
   1.136 +        final SortedMap<String, SortedSet<Dep>> deps;
   1.137          ArchiveDeps(Archive archive) {
   1.138              this.archive = archive;
   1.139 -            this.requireArchives = new HashMap<>();
   1.140              this.deps = new TreeMap<>();
   1.141          }
   1.142  
   1.143 -        void add(String loc) {
   1.144 -            Archive a = map.get(loc);
   1.145 -            if (a == null) {
   1.146 -                map.put(loc, archive);
   1.147 -            } else if (a != archive) {
   1.148 -                // duplicated class warning?
   1.149 -            }
   1.150 -        }
   1.151 -
   1.152 -        void add(String origin, String target) {
   1.153 -            SortedSet<String> set = deps.get(origin);
   1.154 +        void add(String origin, String target, Archive targetArchive, String pkgName) {
   1.155 +            SortedSet<Dep> set = deps.get(origin);
   1.156              if (set == null) {
   1.157                  deps.put(origin, set = new TreeSet<>());
   1.158              }
   1.159 -            if (!set.contains(target)) {
   1.160 -                set.add(target);
   1.161 -                // find the corresponding profile
   1.162 -                Profile p = getTargetProfile(target);
   1.163 -                if (profile == null || (p != null && profile.profile < p.profile)) {
   1.164 -                     profile = p;
   1.165 +            Profile p = targetArchive instanceof JDKArchive
   1.166 +                            ? Profile.getProfile(pkgName) : null;
   1.167 +            set.add(new Dep(target, targetArchive, p));
   1.168 +        }
   1.169 +
   1.170 +        /**
   1.171 +         * Returns the list of Archive dependences.  The returned
   1.172 +         * list contains one {@code Dep} instance per one archive
   1.173 +         * and with the minimum profile this archive depends on.
   1.174 +         */
   1.175 +        List<Dep> requireArchives() {
   1.176 +            Map<Archive,Profile> map = new HashMap<>();
   1.177 +            for (Set<Dep> set: deps.values()) {
   1.178 +                for (Dep d: set) {
   1.179 +                    if (this.archive != d.archive) {
   1.180 +                        Profile p = map.get(d.archive);
   1.181 +                        if (p == null || (d.profile != null && p.profile < d.profile.profile)) {
   1.182 +                            map.put(d.archive, d.profile);
   1.183 +                        }
   1.184 +                    }
   1.185                  }
   1.186              }
   1.187 +            List<Dep> list = new ArrayList<>();
   1.188 +            for (Map.Entry<Archive,Profile> e: map.entrySet()) {
   1.189 +                list.add(new Dep("", e.getKey(), e.getValue()));
   1.190 +            }
   1.191 +            return list;
   1.192 +        }
   1.193 +
   1.194 +        /**
   1.195 +         * Dep represents a dependence where the target can be
   1.196 +         * a classname or packagename and the archive and profile
   1.197 +         * the target belongs to.
   1.198 +         */
   1.199 +        class Dep implements Comparable<Dep> {
   1.200 +            final String target;
   1.201 +            final Archive archive;
   1.202 +            final Profile profile;
   1.203 +            Dep(String target, Archive archive, Profile p) {
   1.204 +                this.target = target;
   1.205 +                this.archive = archive;
   1.206 +                this.profile = p;
   1.207 +            }
   1.208 +
   1.209 +            @Override
   1.210 +            public boolean equals(Object o) {
   1.211 +                if (o instanceof Dep) {
   1.212 +                    Dep d = (Dep)o;
   1.213 +                    return this.archive == d.archive && this.target.equals(d.target);
   1.214 +                }
   1.215 +                return false;
   1.216 +            }
   1.217 +
   1.218 +            @Override
   1.219 +            public int hashCode() {
   1.220 +                int hash = 3;
   1.221 +                hash = 17 * hash + Objects.hashCode(this.archive);
   1.222 +                hash = 17 * hash + Objects.hashCode(this.target);
   1.223 +                return hash;
   1.224 +            }
   1.225 +
   1.226 +            @Override
   1.227 +            public int compareTo(Dep o) {
   1.228 +                if (this.target.equals(o.target)) {
   1.229 +                    if (this.archive == o.archive) {
   1.230 +                        return 0;
   1.231 +                    } else {
   1.232 +                        return this.archive.getFileName().compareTo(o.archive.getFileName());
   1.233 +                    }
   1.234 +                }
   1.235 +                return this.target.compareTo(o.target);
   1.236 +            }
   1.237          }
   1.238          public abstract void visit(Location o, Location t);
   1.239 -        public abstract Profile getTargetProfile(String target);
   1.240      }
   1.241  
   1.242      private class ClassVisitor extends ArchiveDeps {
   1.243          ClassVisitor(Archive archive) {
   1.244              super(archive);
   1.245          }
   1.246 -        public void visit(Location l) {
   1.247 -            add(l.getClassName());
   1.248 -        }
   1.249 +        @Override
   1.250          public void visit(Location o, Location t) {
   1.251 -            add(o.getClassName(), t.getClassName());
   1.252 -        }
   1.253 -        public Profile getTargetProfile(String target) {
   1.254 -            int i = target.lastIndexOf('.');
   1.255 -            return (i > 0) ? Profile.getProfile(target.substring(0, i)) : null;
   1.256 +            Archive targetArchive =
   1.257 +                this.archive.getClasses().contains(t) ? this.archive : map.get(t);
   1.258 +            if (targetArchive == null) {
   1.259 +                map.put(t, targetArchive = NOT_FOUND);
   1.260 +            }
   1.261 +
   1.262 +            String origin = o.getClassName();
   1.263 +            String target = t.getClassName();
   1.264 +            add(origin, target, targetArchive, t.getPackageName());
   1.265          }
   1.266      }
   1.267  
   1.268 @@ -212,18 +250,21 @@
   1.269          PackageVisitor(Archive archive) {
   1.270              super(archive);
   1.271          }
   1.272 +        @Override
   1.273          public void visit(Location o, Location t) {
   1.274 -            add(packageOf(o), packageOf(t));
   1.275 +            Archive targetArchive =
   1.276 +                this.archive.getClasses().contains(t) ? this.archive : map.get(t);
   1.277 +            if (targetArchive == null) {
   1.278 +                map.put(t, targetArchive = NOT_FOUND);
   1.279 +            }
   1.280 +
   1.281 +            String origin = packageOf(o);
   1.282 +            String target = packageOf(t);
   1.283 +            add(origin, target, targetArchive, t.getPackageName());
   1.284          }
   1.285 -        public void visit(Location l) {
   1.286 -            add(packageOf(l));
   1.287 -        }
   1.288 -        private String packageOf(Location loc) {
   1.289 -            String pkg = loc.getPackageName();
   1.290 +        public String packageOf(Location o) {
   1.291 +            String pkg = o.getPackageName();
   1.292              return pkg.isEmpty() ? "<unnamed>" : pkg;
   1.293          }
   1.294 -        public Profile getTargetProfile(String target) {
   1.295 -            return Profile.getProfile(target);
   1.296 -        }
   1.297      }
   1.298  }

mercurial