001: package tide.utils;
002:
003: import tide.editor.*;
004: import tide.sources.*;
005: import snow.concurrent.*;
006: import snow.utils.gui.*;
007: import java.util.*;
008:
009: /** Analyses packages interdependencies.
010: */
011: public final class PackagesDependenciesAnalysis {
012: // name sorted
013: final private Set<PackageNode> packageNodes = new TreeSet<PackageNode>();
014: // usages and dependencies (line i elt uses col j)
015: final private int[][] usages;
016:
017: final String[] names;
018:
019: public int[][] getUsagesMatrix() {
020: return usages;
021: }
022:
023: public String[] getPackageNames() {
024: return names;
025: }
026:
027: public PackagesDependenciesAnalysis(final List<SourceFile> sfs) {
028: HashSet<SourceFile> packages = new HashSet<SourceFile>();
029:
030: // 1) collect all packages
031: for (SourceFile sfi : sfs) {
032: if (sfi.isJavaFile()) // so we not include empty packages !
033: {
034: packages.add((SourceFile) sfi.getParent());
035: }
036: }
037: System.out.println("" + packages.size() + " packages");
038:
039: // create the package nodes
040: for (SourceFile packi : packages) {
041: PackageNode pn = new PackageNode(packi.getPackageName());
042: packageNodes.add(pn);
043:
044: for (int i = 0; i < packi.getChildCount(); i++) {
045: SourceFile ci = packi.getChildFileAt(i);
046: if (ci.isJavaFile()) {
047: pn.directChilds.add(ci);
048: }
049: }
050: }
051:
052: // give them numbers to associate with the matrix
053: int n = 0;
054: names = new String[packageNodes.size()];
055: for (PackageNode pn : packageNodes) {
056: pn.index = n;
057: names[n] = pn.packageName;
058: if (names[n].length() == 0) {
059: names[n] = "<unnamed scope>";
060: }
061: n++;
062: }
063:
064: // fill the dependency matrix (only look at "used by")
065: usages = new int[packageNodes.size()][packageNodes.size()]; // filled with zeroes
066:
067: for (PackageNode pn : packageNodes) {
068: //place the dependencies in the matrix
069: for (SourceFile sfi : pn.directChilds) {
070: for (SourceFile sui : sfi.sourceFileDependencies
071: .getClassesUsedBy_REF_()) // or classesUsingThis
072: {
073: String suipn = sui.getPackageName();
074: PackageNode up = getPackageNode(suipn);
075: if (up != null) {
076: usages[pn.index][up.index]++;
077: }
078: }
079: }
080: }
081:
082: // put 1 on the diagonal, caus a pacj$kage depends on itself (until empty, but
083: // this is not the case). This is important for matrix operations such as
084: // nested dependencies
085: for (int i = 0; i < usages.length; i++) {
086: usages[i][i] = 1;
087: }
088:
089: }
090:
091: @Override
092: public String toString() {
093: StringBuilder sb = new StringBuilder("\t\t");
094: for (int i = 0; i < packageNodes.size(); i++) {
095: sb.append("\t" + (i + 1));
096: }
097: sb.append("\n\t\t");
098: for (PackageNode pn : packageNodes) {
099: sb.append("\t" + pn.packageName);
100: }
101:
102: sb.append("\n");
103:
104: int line = 0;
105: for (PackageNode pn : packageNodes) {
106: sb.append("" + (line + 1) + "\t" + pn.packageName + "\t");
107:
108: for (int col = 0; col < usages[line].length; col++) {
109: sb.append("\t");
110: if (line == col) {
111: //sb.append("\\");
112: } else if (usages[line][col] == 0) {
113:
114: } else {
115: sb.append("" + usages[line][col]);
116: }
117:
118: }
119:
120: sb.append("\n");
121: line++;
122: }
123: return sb.toString();
124: }
125:
126: // Can be boosted with hashtables...
127: private PackageNode getPackageNode(String name) {
128: for (PackageNode pn : packageNodes) {
129: if (pn.packageName.equals(name))
130: return pn;
131: }
132: return null;
133: }
134:
135: class PackageNode implements Comparable<PackageNode> {
136: final String packageName;
137: int index = -1;
138: Set<SourceFile> directChilds = new HashSet<SourceFile>();
139:
140: PackageNode(String name) {
141: this .packageName = name;
142: }
143:
144: public int compareTo(PackageNode pn) {
145: return packageName.compareTo(pn.packageName);
146: }
147: }
148: }
|