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

Fri, 28 Dec 2012 22:25:21 -0800

author
mchung
date
Fri, 28 Dec 2012 22:25:21 -0800
changeset 1472
0c244701188e
child 1577
88286a36bb34
permissions
-rw-r--r--

8003562: Provide a CLI tool to analyze class dependencies
Reviewed-by: jjg, alanb, ulfzibis, erikj

mchung@1472 1 /*
mchung@1472 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
mchung@1472 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mchung@1472 4 *
mchung@1472 5 * This code is free software; you can redistribute it and/or modify it
mchung@1472 6 * under the terms of the GNU General Public License version 2 only, as
mchung@1472 7 * published by the Free Software Foundation. Oracle designates this
mchung@1472 8 * particular file as subject to the "Classpath" exception as provided
mchung@1472 9 * by Oracle in the LICENSE file that accompanied this code.
mchung@1472 10 *
mchung@1472 11 * This code is distributed in the hope that it will be useful, but WITHOUT
mchung@1472 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mchung@1472 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mchung@1472 14 * version 2 for more details (a copy is included in the LICENSE file that
mchung@1472 15 * accompanied this code).
mchung@1472 16 *
mchung@1472 17 * You should have received a copy of the GNU General Public License version
mchung@1472 18 * 2 along with this work; if not, write to the Free Software Foundation,
mchung@1472 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mchung@1472 20 *
mchung@1472 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
mchung@1472 22 * or visit www.oracle.com if you need additional information or have any
mchung@1472 23 * questions.
mchung@1472 24 */
mchung@1472 25 package com.sun.tools.jdeps;
mchung@1472 26
mchung@1472 27 import com.sun.tools.classfile.Dependency;
mchung@1472 28 import com.sun.tools.classfile.Dependency.Location;
mchung@1472 29 import java.io.File;
mchung@1472 30 import java.util.Comparator;
mchung@1472 31 import java.util.HashMap;
mchung@1472 32 import java.util.HashSet;
mchung@1472 33 import java.util.Map;
mchung@1472 34 import java.util.Set;
mchung@1472 35 import java.util.SortedMap;
mchung@1472 36 import java.util.SortedSet;
mchung@1472 37 import java.util.TreeMap;
mchung@1472 38 import java.util.TreeSet;
mchung@1472 39
mchung@1472 40 /**
mchung@1472 41 * Represents the source of the class files.
mchung@1472 42 */
mchung@1472 43 public class Archive {
mchung@1472 44 private static Map<String,Archive> archiveForClass = new HashMap<String,Archive>();
mchung@1472 45 public static Archive find(Location loc) {
mchung@1472 46 return archiveForClass.get(loc.getName());
mchung@1472 47 }
mchung@1472 48
mchung@1472 49 private final File file;
mchung@1472 50 private final String filename;
mchung@1472 51 private final DependencyRecorder recorder;
mchung@1472 52 private final ClassFileReader reader;
mchung@1472 53 public Archive(String name) {
mchung@1472 54 this.file = null;
mchung@1472 55 this.filename = name;
mchung@1472 56 this.recorder = new DependencyRecorder();
mchung@1472 57 this.reader = null;
mchung@1472 58 }
mchung@1472 59
mchung@1472 60 public Archive(File f, ClassFileReader reader) {
mchung@1472 61 this.file = f;
mchung@1472 62 this.filename = f.getName();
mchung@1472 63 this.recorder = new DependencyRecorder();
mchung@1472 64 this.reader = reader;
mchung@1472 65 }
mchung@1472 66
mchung@1472 67 public ClassFileReader reader() {
mchung@1472 68 return reader;
mchung@1472 69 }
mchung@1472 70
mchung@1472 71 public String getFileName() {
mchung@1472 72 return filename;
mchung@1472 73 }
mchung@1472 74
mchung@1472 75 public void addClass(String classFileName) {
mchung@1472 76 Archive a = archiveForClass.get(classFileName);
mchung@1472 77 assert(a == null || a == this); // ## issue warning?
mchung@1472 78 if (!archiveForClass.containsKey(classFileName)) {
mchung@1472 79 archiveForClass.put(classFileName, this);
mchung@1472 80 }
mchung@1472 81 }
mchung@1472 82
mchung@1472 83 public void addDependency(Dependency d) {
mchung@1472 84 recorder.addDependency(d);
mchung@1472 85 }
mchung@1472 86
mchung@1472 87 /**
mchung@1472 88 * Returns a sorted map of a class to its dependencies.
mchung@1472 89 */
mchung@1472 90 public SortedMap<Location, SortedSet<Location>> getDependencies() {
mchung@1472 91 DependencyRecorder.Filter filter = new DependencyRecorder.Filter() {
mchung@1472 92 public boolean accept(Location origin, Location target) {
mchung@1472 93 return (archiveForClass.get(origin.getName()) !=
mchung@1472 94 archiveForClass.get(target.getName()));
mchung@1472 95 }};
mchung@1472 96
mchung@1472 97 SortedMap<Location, SortedSet<Location>> result =
mchung@1472 98 new TreeMap<Location, SortedSet<Location>>(locationComparator);
mchung@1472 99 for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
mchung@1472 100 Location o = e.getKey();
mchung@1472 101 for (Location t : e.getValue()) {
mchung@1472 102 if (filter.accept(o, t)) {
mchung@1472 103 SortedSet<Location> odeps = result.get(o);
mchung@1472 104 if (odeps == null) {
mchung@1472 105 odeps = new TreeSet<Location>(locationComparator);
mchung@1472 106 result.put(o, odeps);
mchung@1472 107 }
mchung@1472 108 odeps.add(t);
mchung@1472 109 }
mchung@1472 110 }
mchung@1472 111 }
mchung@1472 112 return result;
mchung@1472 113 }
mchung@1472 114
mchung@1472 115 /**
mchung@1472 116 * Returns the set of archives this archive requires.
mchung@1472 117 */
mchung@1472 118 public Set<Archive> getRequiredArchives() {
mchung@1472 119 SortedSet<Archive> deps = new TreeSet<Archive>(new Comparator<Archive>() {
mchung@1472 120 public int compare(Archive a1, Archive a2) {
mchung@1472 121 return a1.toString().compareTo(a2.toString());
mchung@1472 122 }
mchung@1472 123 });
mchung@1472 124
mchung@1472 125 for (Map.Entry<Location, Set<Location>> e : recorder.dependencies().entrySet()) {
mchung@1472 126 Location o = e.getKey();
mchung@1472 127 Archive origin = Archive.find(o);
mchung@1472 128 for (Location t : e.getValue()) {
mchung@1472 129 Archive target = Archive.find(t);
mchung@1472 130 assert(origin != null && target != null);
mchung@1472 131 if (origin != target) {
mchung@1472 132 if (!deps.contains(target)) {
mchung@1472 133 deps.add(target);
mchung@1472 134 }
mchung@1472 135 }
mchung@1472 136 }
mchung@1472 137 }
mchung@1472 138 return deps;
mchung@1472 139 }
mchung@1472 140
mchung@1472 141 public String toString() {
mchung@1472 142 return file != null ? file.getPath() : filename;
mchung@1472 143 }
mchung@1472 144
mchung@1472 145 private static class DependencyRecorder {
mchung@1472 146 static interface Filter {
mchung@1472 147 boolean accept(Location origin, Location target);
mchung@1472 148 }
mchung@1472 149
mchung@1472 150 public void addDependency(Dependency d) {
mchung@1472 151 Set<Location> odeps = map.get(d.getOrigin());
mchung@1472 152 if (odeps == null) {
mchung@1472 153 odeps = new HashSet<Location>();
mchung@1472 154 map.put(d.getOrigin(), odeps);
mchung@1472 155 }
mchung@1472 156 odeps.add(d.getTarget());
mchung@1472 157 }
mchung@1472 158
mchung@1472 159 public Map<Location, Set<Location>> dependencies() {
mchung@1472 160 return map;
mchung@1472 161 }
mchung@1472 162
mchung@1472 163 private final Map<Location, Set<Location>> map =
mchung@1472 164 new HashMap<Location, Set<Location>>();
mchung@1472 165 }
mchung@1472 166
mchung@1472 167 private static Comparator<Location> locationComparator =
mchung@1472 168 new Comparator<Location>() {
mchung@1472 169 public int compare(Location o1, Location o2) {
mchung@1472 170 return o1.toString().compareTo(o2.toString());
mchung@1472 171 }
mchung@1472 172 };
mchung@1472 173 }

mercurial