Path: blob/aarch64-shenandoah-jdk8u272-b10/langtools/src/share/classes/com/sun/tools/jdeps/Analyzer.java
38899 views
/*1* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package com.sun.tools.jdeps;2526import java.util.HashMap;27import java.util.HashSet;28import java.util.List;29import java.util.Map;30import java.util.Objects;31import java.util.Set;32import java.util.SortedMap;33import java.util.SortedSet;34import java.util.TreeMap;35import java.util.TreeSet;3637import com.sun.tools.classfile.Dependency.Location;38import com.sun.tools.jdeps.PlatformClassPath.JDKArchive;3940/**41* Dependency Analyzer.42*/43public class Analyzer {44/**45* Type of the dependency analysis. Appropriate level of data46* will be stored.47*/48public enum Type {49SUMMARY,50PACKAGE,51CLASS,52VERBOSE53};5455/**56* Filter to be applied when analyzing the dependencies from the given archives.57* Only the accepted dependencies are recorded.58*/59interface Filter {60boolean accepts(Location origin, Archive originArchive, Location target, Archive targetArchive);61}6263private final Type type;64private final Filter filter;65private final Map<Archive, ArchiveDeps> results = new HashMap<>();66private final Map<Location, Archive> map = new HashMap<>();67private final Archive NOT_FOUND68= new Archive(JdepsTask.getMessage("artifact.not.found"));6970/**71* Constructs an Analyzer instance.72*73* @param type Type of the dependency analysis74* @param filter75*/76public Analyzer(Type type, Filter filter) {77this.type = type;78this.filter = filter;79}8081/**82* Performs the dependency analysis on the given archives.83*/84public void run(List<Archive> archives) {85// build a map from Location to Archive86buildLocationArchiveMap(archives);8788// traverse and analyze all dependencies89for (Archive archive : archives) {90ArchiveDeps deps = new ArchiveDeps(archive, type);91archive.visitDependences(deps);92results.put(archive, deps);93}94}9596private void buildLocationArchiveMap(List<Archive> archives) {97// build a map from Location to Archive98for (Archive archive: archives) {99for (Location l: archive.getClasses()) {100if (!map.containsKey(l)) {101map.put(l, archive);102} else {103// duplicated class warning?104}105}106}107}108109public boolean hasDependences(Archive archive) {110if (results.containsKey(archive)) {111return results.get(archive).dependencies().size() > 0;112}113return false;114}115116public Set<String> dependences(Archive source) {117ArchiveDeps result = results.get(source);118return result.targetDependences();119}120121public interface Visitor {122/**123* Visits a recorded dependency from origin to target which can be124* a fully-qualified classname, a package name, a module or125* archive name depending on the Analyzer's type.126*/127public void visitDependence(String origin, Archive originArchive,128String target, Archive targetArchive);129}130131/**132* Visit the dependencies of the given source.133* If the requested level is SUMMARY, it will visit the required archives list.134*/135public void visitDependences(Archive source, Visitor v, Type level) {136if (level == Type.SUMMARY) {137final ArchiveDeps result = results.get(source);138SortedMap<String, Archive> sorted = new TreeMap<>();139for (Archive a : result.requires()) {140sorted.put(a.getName(), a);141}142for (Archive archive : sorted.values()) {143Profile profile = result.getTargetProfile(archive);144v.visitDependence(source.getName(), source,145profile != null ? profile.profileName() : archive.getName(), archive);146}147} else {148ArchiveDeps result = results.get(source);149if (level != type) {150// requesting different level of analysis151result = new ArchiveDeps(source, level);152source.visitDependences(result);153}154SortedSet<Dep> sorted = new TreeSet<>(result.dependencies());155for (Dep d : sorted) {156v.visitDependence(d.origin(), d.originArchive(), d.target(), d.targetArchive());157}158}159}160161public void visitDependences(Archive source, Visitor v) {162visitDependences(source, v, type);163}164165/**166* ArchiveDeps contains the dependencies for an Archive that can have one or167* more classes.168*/169class ArchiveDeps implements Archive.Visitor {170protected final Archive archive;171protected final Set<Archive> requires;172protected final Set<Dep> deps;173protected final Type level;174private Profile profile;175ArchiveDeps(Archive archive, Type level) {176this.archive = archive;177this.deps = new HashSet<>();178this.requires = new HashSet<>();179this.level = level;180}181182Set<Dep> dependencies() {183return deps;184}185186Set<String> targetDependences() {187Set<String> targets = new HashSet<>();188for (Dep d : deps) {189targets.add(d.target());190}191return targets;192}193194Set<Archive> requires() {195return requires;196}197198Profile getTargetProfile(Archive target) {199return JDKArchive.isProfileArchive(target) ? profile : null;200}201202Archive findArchive(Location t) {203Archive target = archive.getClasses().contains(t) ? archive : map.get(t);204if (target == null) {205map.put(t, target = NOT_FOUND);206}207return target;208}209210// return classname or package name depedning on the level211private String getLocationName(Location o) {212if (level == Type.CLASS || level == Type.VERBOSE) {213return o.getClassName();214} else {215String pkg = o.getPackageName();216return pkg.isEmpty() ? "<unnamed>" : pkg;217}218}219220@Override221public void visit(Location o, Location t) {222Archive targetArchive = findArchive(t);223if (filter.accepts(o, archive, t, targetArchive)) {224addDep(o, t);225if (archive != targetArchive && !requires.contains(targetArchive)) {226requires.add(targetArchive);227}228}229if (targetArchive instanceof JDKArchive) {230Profile p = Profile.getProfile(t.getPackageName());231if (profile == null || (p != null && p.compareTo(profile) > 0)) {232profile = p;233}234}235}236237private Dep curDep;238protected Dep addDep(Location o, Location t) {239String origin = getLocationName(o);240String target = getLocationName(t);241Archive targetArchive = findArchive(t);242if (curDep != null &&243curDep.origin().equals(origin) &&244curDep.originArchive() == archive &&245curDep.target().equals(target) &&246curDep.targetArchive() == targetArchive) {247return curDep;248}249250Dep e = new Dep(origin, archive, target, targetArchive);251if (deps.contains(e)) {252for (Dep e1 : deps) {253if (e.equals(e1)) {254curDep = e1;255}256}257} else {258deps.add(e);259curDep = e;260}261return curDep;262}263}264265/*266* Class-level or package-level dependency267*/268class Dep implements Comparable<Dep> {269final String origin;270final Archive originArchive;271final String target;272final Archive targetArchive;273274Dep(String origin, Archive originArchive, String target, Archive targetArchive) {275this.origin = origin;276this.originArchive = originArchive;277this.target = target;278this.targetArchive = targetArchive;279}280281String origin() {282return origin;283}284285Archive originArchive() {286return originArchive;287}288289String target() {290return target;291}292293Archive targetArchive() {294return targetArchive;295}296297@Override298@SuppressWarnings("unchecked")299public boolean equals(Object o) {300if (o instanceof Dep) {301Dep d = (Dep) o;302return this.origin.equals(d.origin) &&303this.originArchive == d.originArchive &&304this.target.equals(d.target) &&305this.targetArchive == d.targetArchive;306}307return false;308}309310@Override311public int hashCode() {312int hash = 7;313hash = 67*hash + Objects.hashCode(this.origin)314+ Objects.hashCode(this.originArchive)315+ Objects.hashCode(this.target)316+ Objects.hashCode(this.targetArchive);317return hash;318}319320@Override321public int compareTo(Dep o) {322if (this.origin.equals(o.origin)) {323if (this.target.equals(o.target)) {324if (this.originArchive == o.originArchive &&325this.targetArchive == o.targetArchive) {326return 0;327} else if (this.originArchive == o.originArchive) {328return this.targetArchive.getPathName().compareTo(o.targetArchive.getPathName());329} else {330return this.originArchive.getPathName().compareTo(o.originArchive.getPathName());331}332} else {333return this.target.compareTo(o.target);334}335}336return this.origin.compareTo(o.origin);337}338}339}340341342