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

Fri, 09 May 2014 20:33:21 -0700

author
mfang
date
Fri, 09 May 2014 20:33:21 -0700
changeset 2388
0add97444be9
parent 2172
aa91bc6e8480
child 2525
2eb010b6cb22
child 2538
1e39ae45d8ac
permissions
-rw-r--r--

8041424: 8u20 l10n resource file translation update 1
Reviewed-by: naoto, yhuang

     1 /*
     2  * Copyright (c) 2013, 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 package com.sun.tools.jdeps;
    27 import com.sun.tools.classfile.Dependency.Location;
    28 import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;
    29 import java.util.ArrayList;
    30 import java.util.HashMap;
    31 import java.util.List;
    32 import java.util.Map;
    33 import java.util.Objects;
    34 import java.util.Set;
    35 import java.util.SortedMap;
    36 import java.util.SortedSet;
    37 import java.util.TreeMap;
    38 import java.util.TreeSet;
    40 /**
    41  * Dependency Analyzer.
    42  */
    43 public class Analyzer {
    44     /**
    45      * Type of the dependency analysis.  Appropriate level of data
    46      * will be stored.
    47      */
    48     public enum Type {
    49         SUMMARY,
    50         PACKAGE,
    51         CLASS,
    52         VERBOSE
    53     };
    55     private final Type type;
    56     private final Map<Archive, ArchiveDeps> results = new HashMap<>();
    57     private final Map<Location, Archive> map = new HashMap<>();
    58     private final Archive NOT_FOUND
    59         = new Archive(JdepsTask.getMessage("artifact.not.found"));
    61     /**
    62      * Constructs an Analyzer instance.
    63      *
    64      * @param type Type of the dependency analysis
    65      */
    66     public Analyzer(Type type) {
    67         this.type = type;
    68     }
    70     /**
    71      * Performs the dependency analysis on the given archives.
    72      */
    73     public void run(List<Archive> archives) {
    74         // build a map from Location to Archive
    75         for (Archive archive: archives) {
    76             for (Location l: archive.getClasses()) {
    77                 if (!map.containsKey(l)) {
    78                     map.put(l, archive);
    79                 } else {
    80                     // duplicated class warning?
    81                 }
    82             }
    83         }
    84         // traverse and analyze all dependencies
    85         for (Archive archive : archives) {
    86             ArchiveDeps deps;
    87             if (type == Type.CLASS || type == Type.VERBOSE) {
    88                 deps = new ClassVisitor(archive);
    89             } else {
    90                 deps = new PackageVisitor(archive);
    91             }
    92             archive.visitDependences(deps);
    93             results.put(archive, deps);
    94         }
    95     }
    97     public boolean hasDependences(Archive archive) {
    98         if (results.containsKey(archive)) {
    99             return results.get(archive).deps.size() > 0;
   100         }
   101         return false;
   102     }
   104     public interface Visitor {
   105         /**
   106          * Visits the source archive to its destination archive of
   107          * a recorded dependency.
   108          */
   109         void visitArchiveDependence(Archive origin, Archive target, Profile profile);
   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 visitDependence(String origin, Archive source, String target, Archive archive, Profile profile);
   116     }
   118     public void visitArchiveDependences(Archive source, Visitor v) {
   119         ArchiveDeps r = results.get(source);
   120         for (ArchiveDeps.Dep d: r.requireArchives()) {
   121             v.visitArchiveDependence(r.archive, d.archive, d.profile);
   122         }
   123     }
   125     public void visitDependences(Archive source, Visitor v) {
   126         ArchiveDeps r = results.get(source);
   127         for (Map.Entry<String, SortedSet<ArchiveDeps.Dep>> e: r.deps.entrySet()) {
   128             String origin = e.getKey();
   129             for (ArchiveDeps.Dep d: e.getValue()) {
   130                 // filter intra-dependency unless in verbose mode
   131                 if (type == Type.VERBOSE || d.archive != source) {
   132                     v.visitDependence(origin, source, d.target, d.archive, d.profile);
   133                 }
   134             }
   135         }
   136     }
   138     /**
   139      * ArchiveDeps contains the dependencies for an Archive that
   140      * can have one or more classes.
   141      */
   142     private abstract class ArchiveDeps implements Archive.Visitor {
   143         final Archive archive;
   144         final SortedMap<String, SortedSet<Dep>> deps;
   145         ArchiveDeps(Archive archive) {
   146             this.archive = archive;
   147             this.deps = new TreeMap<>();
   148         }
   150         void add(String origin, String target, Archive targetArchive, String pkgName) {
   151             SortedSet<Dep> set = deps.get(origin);
   152             if (set == null) {
   153                 deps.put(origin, set = new TreeSet<>());
   154             }
   155             Profile p = targetArchive instanceof JDKArchive
   156                             ? Profile.getProfile(pkgName) : null;
   157             set.add(new Dep(target, targetArchive, p));
   158         }
   160         /**
   161          * Returns the list of Archive dependences.  The returned
   162          * list contains one {@code Dep} instance per one archive
   163          * and with the minimum profile this archive depends on.
   164          */
   165         List<Dep> requireArchives() {
   166             Map<Archive,Profile> map = new HashMap<>();
   167             for (Set<Dep> set: deps.values()) {
   168                 for (Dep d: set) {
   169                     if (this.archive != d.archive) {
   170                         Profile p = map.get(d.archive);
   171                         if (p == null || (d.profile != null && p.profile < d.profile.profile)) {
   172                             map.put(d.archive, d.profile);
   173                         }
   174                     }
   175                 }
   176             }
   177             List<Dep> list = new ArrayList<>();
   178             for (Map.Entry<Archive,Profile> e: map.entrySet()) {
   179                 list.add(new Dep("", e.getKey(), e.getValue()));
   180             }
   181             return list;
   182         }
   184         /**
   185          * Dep represents a dependence where the target can be
   186          * a classname or packagename and the archive and profile
   187          * the target belongs to.
   188          */
   189         class Dep implements Comparable<Dep> {
   190             final String target;
   191             final Archive archive;
   192             final Profile profile;
   193             Dep(String target, Archive archive, Profile p) {
   194                 this.target = target;
   195                 this.archive = archive;
   196                 this.profile = p;
   197             }
   199             @Override
   200             public boolean equals(Object o) {
   201                 if (o instanceof Dep) {
   202                     Dep d = (Dep)o;
   203                     return this.archive == d.archive && this.target.equals(d.target);
   204                 }
   205                 return false;
   206             }
   208             @Override
   209             public int hashCode() {
   210                 int hash = 3;
   211                 hash = 17 * hash + Objects.hashCode(this.archive);
   212                 hash = 17 * hash + Objects.hashCode(this.target);
   213                 return hash;
   214             }
   216             @Override
   217             public int compareTo(Dep o) {
   218                 if (this.target.equals(o.target)) {
   219                     if (this.archive == o.archive) {
   220                         return 0;
   221                     } else {
   222                         return this.archive.getFileName().compareTo(o.archive.getFileName());
   223                     }
   224                 }
   225                 return this.target.compareTo(o.target);
   226             }
   227         }
   228         public abstract void visit(Location o, Location t);
   229     }
   231     private class ClassVisitor extends ArchiveDeps {
   232         ClassVisitor(Archive archive) {
   233             super(archive);
   234         }
   235         @Override
   236         public void visit(Location o, Location t) {
   237             Archive targetArchive =
   238                 this.archive.getClasses().contains(t) ? this.archive : map.get(t);
   239             if (targetArchive == null) {
   240                 map.put(t, targetArchive = NOT_FOUND);
   241             }
   243             String origin = o.getClassName();
   244             String target = t.getClassName();
   245             add(origin, target, targetArchive, t.getPackageName());
   246         }
   247     }
   249     private class PackageVisitor extends ArchiveDeps {
   250         PackageVisitor(Archive archive) {
   251             super(archive);
   252         }
   253         @Override
   254         public void visit(Location o, Location t) {
   255             Archive targetArchive =
   256                 this.archive.getClasses().contains(t) ? this.archive : map.get(t);
   257             if (targetArchive == null) {
   258                 map.put(t, targetArchive = NOT_FOUND);
   259             }
   261             String origin = packageOf(o);
   262             String target = packageOf(t);
   263             add(origin, target, targetArchive, t.getPackageName());
   264         }
   265         public String packageOf(Location o) {
   266             String pkg = o.getPackageName();
   267             return pkg.isEmpty() ? "<unnamed>" : pkg;
   268         }
   269     }
   270 }

mercurial