diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
commit | 13d05bc8458758ee39cb829098241e89616717ee (patch) | |
tree | 22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java | |
parent | 6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff) |
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java')
-rw-r--r-- | framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java new file mode 100644 index 00000000..a210d717 --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyViewer.java @@ -0,0 +1,188 @@ +package org.onlab.jdvue; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.io.BufferedReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Set; + +/** + * Generator of a self-contained HTML file which serves as a GUI for + * visualizing Java package dependencies carried in the supplied catalog. + * + * The HTML file is an adaptation of D3.js Hierarchical Edge Bundling as + * shown at http://bl.ocks.org/mbostock/7607999. + * + * @author Thomas Vachuska + */ +public class DependencyViewer { + + private static final String JPD_EXT = ".db"; + private static final String HTML_EXT = ".html"; + + private static final String INDEX = "index.html"; + private static final String D3JS = "d3.v3.min.js"; + + private static final String TITLE_PLACEHOLDER = "TITLE_PLACEHOLDER"; + private static final String D3JS_PLACEHOLDER = "D3JS_PLACEHOLDER"; + private static final String DATA_PLACEHOLDER = "DATA_PLACEHOLDER"; + + private final Catalog catalog; + + /** + * Creates a Java package dependency viewer. + * + * @param catalog dependency catalog + */ + public DependencyViewer(Catalog catalog) { + this.catalog = catalog; + } + + /** + * Main program entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + Catalog cat = new Catalog(); + DependencyViewer viewer = new DependencyViewer(cat); + try { + String path = args[0]; + cat.load(path + JPD_EXT); + cat.analyze(); + + System.err.println(cat); + viewer.dumpLongestCycle(cat); + viewer.writeHTMLFile(path); + } catch (IOException e) { + System.err.println("Unable to process catalog: " + e.getMessage()); + } + } + + /** + * Prints out the longest cycle; just for kicks. + * @param cat catalog + */ + private void dumpLongestCycle(Catalog cat) { + DependencyCycle longest = null; + for (DependencyCycle cycle : cat.getCycles()) { + if (longest == null || longest.getCycleSegments().size() < cycle.getCycleSegments().size()) { + longest = cycle; + } + } + + if (longest != null) { + for (Dependency dependency : longest.getCycleSegments()) { + System.out.println(dependency); + } + } + } + + /** + * Writes the HTML catalog file for the given viewer. + * + * @param path base file path + * @throws IOException if issues encountered writing the HTML file + */ + public void writeHTMLFile(String path) throws IOException { + String index = slurp(getClass().getResourceAsStream(INDEX)); + String d3js = slurp(getClass().getResourceAsStream(D3JS)); + + FileWriter fw = new FileWriter(path + HTML_EXT); + ObjectWriter writer = new ObjectMapper().writer(); // .writerWithDefaultPrettyPrinter(); + fw.write(index.replace(TITLE_PLACEHOLDER, path) + .replace(D3JS_PLACEHOLDER, d3js) + .replace(DATA_PLACEHOLDER, writer.writeValueAsString(toJson()))); + fw.close(); + } + + /** + * Slurps the specified input stream into a string. + * + * @param stream input stream to be read + * @return string containing the contents of the input stream + * @throws IOException if issues encountered reading from the stream + */ + static String slurp(InputStream stream) throws IOException { + StringBuilder sb = new StringBuilder(); + BufferedReader br = new BufferedReader(new InputStreamReader(stream)); + String line; + while ((line = br.readLine()) != null) { + sb.append(line).append(System.lineSeparator()); + } + br.close(); + return sb.toString(); + } + + // Produces a JSON structure designed to drive the hierarchical visual + // representation of Java package dependencies and any dependency cycles + private JsonNode toJson() { + ObjectMapper mapper = new ObjectMapper(); + ObjectNode root = mapper.createObjectNode(); + root.put("packages", jsonPackages(mapper)); + root.put("cycleSegments", jsonCycleSegments(mapper, catalog.getCycleSegments())); + root.put("summary", jsonSummary(mapper)); + return root; + } + + // Produces a JSON summary of dependencies + private JsonNode jsonSummary(ObjectMapper mapper) { + ObjectNode summary = mapper.createObjectNode(); + summary.put("packages", catalog.getPackages().size()); + summary.put("sources", catalog.getSources().size()); + summary.put("cycles", catalog.getCycles().size()); + summary.put("cycleSegments", catalog.getCycleSegments().size()); + return summary; + } + + // Produces a JSON structure with package dependency data + private JsonNode jsonPackages(ObjectMapper mapper) { + ArrayNode packages = mapper.createArrayNode(); + for (JavaPackage javaPackage : catalog.getPackages()) { + packages.add(json(mapper, javaPackage)); + } + return packages; + } + + // Produces a JSON structure with all cyclic segments + private JsonNode jsonCycleSegments(ObjectMapper mapper, + Set<Dependency> segments) { + ObjectNode cyclicSegments = mapper.createObjectNode(); + for (Dependency dependency : segments) { + String s = dependency.getSource().name(); + String t = dependency.getTarget().name(); + cyclicSegments.put(t + "-" + s, + mapper.createObjectNode().put("s", s).put("t", t)); + } + return cyclicSegments; + } + + // Produces a JSON object structure describing the specified Java package. + private JsonNode json(ObjectMapper mapper, JavaPackage javaPackage) { + ObjectNode node = mapper.createObjectNode(); + + ArrayNode imports = mapper.createArrayNode(); + for (JavaPackage dependency : javaPackage.getDependencies()) { + imports.add(dependency.name()); + } + + Set<DependencyCycle> packageCycles = catalog.getPackageCycles(javaPackage); + Set<Dependency> packageCycleSegments = catalog.getPackageCycleSegments(javaPackage); + + node.put("name", javaPackage.name()); + node.put("size", javaPackage.getSources().size()); + node.put("imports", imports); + node.put("cycleSegments", jsonCycleSegments(mapper, packageCycleSegments)); + node.put("cycleCount", packageCycles.size()); + node.put("cycleSegmentCount", packageCycleSegments.size()); + return node; + } + +} |