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

Tue, 17 Sep 2013 14:17:13 -0700

author
jjg
date
Tue, 17 Sep 2013 14:17:13 -0700
changeset 2033
fdfbc5f0c4ed
parent 1638
fd3fdaff0257
child 2139
defadd528513
permissions
-rw-r--r--

8024538: -Xdoclint + -Xprefer:source + incremental compilation == FAIL
Reviewed-by: darcy

     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 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;
    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     };
    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"));
    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     }
    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         }
    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     }
   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     }
   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     }
   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     }
   150     public Archive getArchive(String name) {
   151         return map.containsKey(name) ? map.get(name) : NOT_FOUND;
   152     }
   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     }
   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;
   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         }
   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         }
   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         }
   199         public abstract void visit(Location o, Location t);
   200         public abstract String getTargetProfile(String target);
   202     }
   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     }
   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 }

mercurial