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 | |
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')
8 files changed, 1007 insertions, 0 deletions
diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java new file mode 100644 index 00000000..8f611c52 --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Catalog.java @@ -0,0 +1,391 @@ +package org.onlab.jdvue; + + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Produces a package & source catalogue. + * + * @author Thomas Vachuska + */ +public class Catalog { + + private static final String PACKAGE = "package"; + private static final String IMPORT = "import"; + private static final String STATIC = "static"; + private static final String SRC_ROOT = "src/main/java/"; + private static final String WILDCARD = "\\.*$"; + + private final Map<String, JavaSource> sources = new HashMap<>(); + private final Map<String, JavaPackage> packages = new HashMap<>(); + private final Set<DependencyCycle> cycles = new HashSet<>(); + private final Set<Dependency> cycleSegments = new HashSet<>(); + private final Map<JavaPackage, Set<DependencyCycle>> packageCycles = new HashMap<>(); + private final Map<JavaPackage, Set<Dependency>> packageCycleSegments = new HashMap<>(); + + /** + * Loads the catalog from the specified catalog file. + * + * @param catalogPath catalog file path + * @throws IOException if unable to read the catalog file + */ + public void load(String catalogPath) throws IOException { + InputStream is = new FileInputStream(catalogPath); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + + String line; + while ((line = br.readLine()) != null) { + // Split the line into the two fields: path and pragmas + String fields[] = line.trim().split(":"); + if (fields.length <= 1) { + continue; + } + String path = fields[0]; + + // Now split the pragmas on whitespace and trim punctuation + String pragma[] = fields[1].trim().replaceAll("[;\n\r]", "").split("[\t ]"); + + // Locate (or create) Java source entity based on the path + JavaSource source = getOrCreateSource(path); + + // Now process the package or import statements + if (pragma[0].equals(PACKAGE)) { + processPackageDeclaration(source, pragma[1]); + + } else if (pragma[0].equals(IMPORT)) { + if (pragma[1].equals(STATIC)) { + processImportStatement(source, pragma[2]); + } else { + processImportStatement(source, pragma[1]); + } + } + } + } + + /** + * Analyzes the catalog by resolving imports and identifying circular + * package dependencies. + */ + public void analyze() { + resolveImports(); + findCircularDependencies(); + } + + /** + * Identifies circular package dependencies through what amounts to be a + * depth-first search rooted with each package. + */ + private void findCircularDependencies() { + cycles.clear(); + for (JavaPackage javaPackage : getPackages()) { + findCircularDependencies(javaPackage); + } + + cycleSegments.clear(); + packageCycles.clear(); + packageCycleSegments.clear(); + + for (DependencyCycle cycle : getCycles()) { + recordCycleForPackages(cycle); + cycleSegments.addAll(cycle.getCycleSegments()); + } + } + + /** + * Records the specified cycle into a set for each involved package. + * + * @param cycle cycle to record for involved packages + */ + private void recordCycleForPackages(DependencyCycle cycle) { + for (JavaPackage javaPackage : cycle.getCycle()) { + Set<DependencyCycle> cset = packageCycles.get(javaPackage); + if (cset == null) { + cset = new HashSet<>(); + packageCycles.put(javaPackage, cset); + } + cset.add(cycle); + + Set<Dependency> sset = packageCycleSegments.get(javaPackage); + if (sset == null) { + sset = new HashSet<>(); + packageCycleSegments.put(javaPackage, sset); + } + sset.addAll(cycle.getCycleSegments()); + } + } + + /** + * Identifies circular dependencies in which this package participates + * using depth-first search. + * + * @param javaPackage Java package to inspect for dependency cycles + */ + private void findCircularDependencies(JavaPackage javaPackage) { + // Setup a depth trace anchored at the given java package. + List<JavaPackage> trace = newTrace(new ArrayList<JavaPackage>(), javaPackage); + + Set<JavaPackage> searched = new HashSet<>(); + searchDependencies(javaPackage, trace, searched); + } + + /** + * Generates a new trace using the previous one and a new element + * + * @param trace old search trace + * @param javaPackage package to add to the trace + * @return new search trace + */ + private List<JavaPackage> newTrace(List<JavaPackage> trace, + JavaPackage javaPackage) { + List<JavaPackage> newTrace = new ArrayList<>(trace); + newTrace.add(javaPackage); + return newTrace; + } + + + /** + * Recursive depth-first search through dependency tree + * + * @param javaPackage java package being searched currently + * @param trace search trace + * @param searched set of java packages already searched + */ + private void searchDependencies(JavaPackage javaPackage, + List<JavaPackage> trace, + Set<JavaPackage> searched) { + if (!searched.contains(javaPackage)) { + searched.add(javaPackage); + for (JavaPackage dependency : javaPackage.getDependencies()) { + if (trace.contains(dependency)) { + cycles.add(new DependencyCycle(trace, dependency)); + } else { + searchDependencies(dependency, newTrace(trace, dependency), searched); + } + } + } + } + + /** + * Resolves import names of Java sources into imports of entities known + * to this catalog. All other import names will be ignored. + */ + private void resolveImports() { + for (JavaPackage javaPackage : getPackages()) { + Set<JavaPackage> dependencies = new HashSet<>(); + for (JavaSource source : javaPackage.getSources()) { + Set<JavaEntity> imports = resolveImports(source); + source.setImports(imports); + dependencies.addAll(importedPackages(imports)); + } + javaPackage.setDependencies(dependencies); + } + } + + /** + * Produces a set of imported Java packages from the specified set of + * Java source entities. + * + * @param imports list of imported Java source entities + * @return list of imported Java packages + */ + private Set<JavaPackage> importedPackages(Set<JavaEntity> imports) { + Set<JavaPackage> packages = new HashSet<>(); + for (JavaEntity entity : imports) { + packages.add(entity instanceof JavaPackage ? (JavaPackage) entity : + ((JavaSource) entity).getPackage()); + } + return packages; + } + + /** + * Resolves import names of the specified Java source into imports of + * entities known to this catalog. All other import names will be ignored. + * + * @param source Java source + * @return list of resolved imports + */ + private Set<JavaEntity> resolveImports(JavaSource source) { + Set<JavaEntity> imports = new HashSet<>(); + for (String importName : source.getImportNames()) { + JavaEntity entity = importName.matches(WILDCARD) ? + getPackage(importName.replaceAll(WILDCARD, "")) : + getSource(importName); + if (entity != null) { + imports.add(entity); + } + } + return imports; + } + + /** + * Returns either an existing or a newly created Java package. + * + * @param packageName Java package name + * @return Java package + */ + private JavaPackage getOrCreatePackage(String packageName) { + JavaPackage javaPackage = packages.get(packageName); + if (javaPackage == null) { + javaPackage = new JavaPackage(packageName); + packages.put(packageName, javaPackage); + } + return javaPackage; + } + + /** + * Returns either an existing or a newly created Java source. + * + * @param path Java source path + * @return Java source + */ + private JavaSource getOrCreateSource(String path) { + String name = nameFromPath(path); + JavaSource source = sources.get(name); + if (source == null) { + source = new JavaSource(name, path); + sources.put(name, source); + } + return source; + } + + /** + * Extracts a fully qualified source class name from the given path. + * <p/> + * For now, this implementation assumes standard Maven source structure + * and thus will look for start of package name under 'src/main/java/'. + * If it will not find such a prefix, it will simply return the path as + * the name. + * + * @param path source path + * @return source name + */ + private String nameFromPath(String path) { + int i = path.indexOf(SRC_ROOT); + String name = i < 0 ? path : path.substring(i + SRC_ROOT.length()); + return name.replaceAll("\\.java$", "").replace("/", "."); + } + + /** + * Processes the package declaration pragma for the given source. + * + * @param source Java source + * @param packageName Java package name + */ + private void processPackageDeclaration(JavaSource source, String packageName) { + JavaPackage javaPackage = getOrCreatePackage(packageName); + source.setPackage(javaPackage); + javaPackage.addSource(source); + } + + /** + * Processes the import pragma for the given source. + * + * @param source Java source + * @param name name of the Java entity being imported (class or package) + */ + private void processImportStatement(JavaSource source, String name) { + source.addImportName(name); + } + + /** + * Returns the collection of java sources. + * + * @return collection of java sources + */ + public Collection<JavaSource> getSources() { + return Collections.unmodifiableCollection(sources.values()); + } + + /** + * Returns the Java source with the specified name. + * + * @param name Java source name + * @return Java source + */ + public JavaSource getSource(String name) { + return sources.get(name); + } + + /** + * Returns the collection of all Java packages. + * + * @return collection of java packages + */ + public Collection<JavaPackage> getPackages() { + return Collections.unmodifiableCollection(packages.values()); + } + + /** + * Returns the set of all Java package dependency cycles. + * + * @return set of dependency cycles + */ + public Set<DependencyCycle> getCycles() { + return Collections.unmodifiableSet(cycles); + } + + /** + * Returns the set of all Java package dependency cycle segments. + * + * @return set of dependency cycle segments + */ + public Set<Dependency> getCycleSegments() { + return Collections.unmodifiableSet(cycleSegments); + } + + /** + * Returns the set of dependency cycles which involve the specified package. + * + * @param javaPackage java package + * @return set of dependency cycles + */ + public Set<DependencyCycle> getPackageCycles(JavaPackage javaPackage) { + Set<DependencyCycle> set = packageCycles.get(javaPackage); + return Collections.unmodifiableSet(set == null ? new HashSet<DependencyCycle>() : set); + } + + /** + * Returns the set of dependency cycle segments which involve the specified package. + * + * @param javaPackage java package + * @return set of dependency cycle segments + */ + public Set<Dependency> getPackageCycleSegments(JavaPackage javaPackage) { + Set<Dependency> set = packageCycleSegments.get(javaPackage); + return Collections.unmodifiableSet(set == null ? new HashSet<Dependency>() : set); + } + + /** + * Returns the Java package with the specified name. + * + * @param name Java package name + * @return Java package + */ + public JavaPackage getPackage(String name) { + return packages.get(name); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("packages", packages.size()) + .add("sources", sources.size()) + .add("cycles", cycles.size()) + .add("cycleSegments", cycleSegments.size()).toString(); + } + +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java new file mode 100644 index 00000000..7fc3409a --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/Dependency.java @@ -0,0 +1,67 @@ +package org.onlab.jdvue; + +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Abstraction of a dependency segment. + * + * @author Thomas Vachuska + */ +public class Dependency { + + private final JavaPackage source; + private final JavaPackage target; + + /** + * Creates a dependency from the specified source on the given target. + * + * @param source source of the dependency + * @param target target of the dependency + */ + public Dependency(JavaPackage source, JavaPackage target) { + this.source = source; + this.target = target; + } + + /** + * Returns the dependency source. + * + * @return source Java package + */ + public JavaPackage getSource() { + return source; + } + + /** + * Returns the dependency target. + * + * @return target Java package + */ + public JavaPackage getTarget() { + return target; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Dependency) { + Dependency that = (Dependency) obj; + return Objects.equals(source, that.source) && + Objects.equals(target, that.target); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(source, target); + } + + @Override + public String toString() { + return toStringHelper(this) + .add("source", source).add("target", target).toString(); + } + +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java new file mode 100644 index 00000000..65e3cfbc --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/DependencyCycle.java @@ -0,0 +1,118 @@ +package org.onlab.jdvue; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Simple representation of a Java package dependency cycle. + */ +public class DependencyCycle { + + private final List<JavaPackage> cycle; + + /** + * Creates a normalized dependency cycle represented by the specified list + * of Java packages, which are expected to be given in order of dependency. + * List is assumed to be non-empty. + * + * @param cycle list of Java packages in the dependency cycle + * @param cause Java package that caused the cycle + */ + DependencyCycle(List<JavaPackage> cycle, JavaPackage cause) { + this.cycle = normalize(cycle, cause); + } + + /** + * Produces a normalized dependency cycle list. Normalization is performed + * by rotating the list so that the package with the least lexicographic + * name is at the start of the list. + * + * @param cycle list of Java packages in the dependency cycle + * @param cause Java package that caused the cycle + * @return normalized cycle + */ + private List<JavaPackage> normalize(List<JavaPackage> cycle, JavaPackage cause) { + int start = cycle.indexOf(cause); + List<JavaPackage> clone = new ArrayList<>(cycle.subList(start, cycle.size())); + int leastIndex = findIndexOfLeastName(clone); + Collections.rotate(clone, -leastIndex); + return Collections.unmodifiableList(clone); + } + + /** + * Returns the index of the Java package with the least name. + * + * @param cycle list of Java packages in the dependency cycle + * @return index of the least Java package name + */ + private int findIndexOfLeastName(List<JavaPackage> cycle) { + int leastIndex = 0; + String leastName = cycle.get(leastIndex).name(); + for (int i = 1, n = cycle.size(); i < n; i++) { + JavaPackage javaPackage = cycle.get(i); + if (leastName.compareTo(javaPackage.name()) > 0) { + leastIndex = i; + leastName = javaPackage.name(); + } + } + return leastIndex; + } + + /** + * Returns the normalized Java package dependency cycle + * + * @return list of packages in the dependency cycle + */ + public List<JavaPackage> getCycle() { + return cycle; + } + + /** + * Returns the dependency cycle in form of individual dependencies. + * + * @return list of dependencies forming the cycle + */ + public List<Dependency> getCycleSegments() { + List<Dependency> dependencies = new ArrayList<>(); + for (int i = 0, n = cycle.size(); i < n; i++) { + dependencies.add(new Dependency(cycle.get(i), cycle.get(i < n - 1 ? i + 1 : 0))); + } + return dependencies; + } + + @Override + public boolean equals(Object o) { + if (o instanceof DependencyCycle) { + DependencyCycle that = (DependencyCycle) o; + return Objects.equals(cycle, that.cycle); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(cycle); + } + + @Override + public String toString() { + return toStringHelper(this).add("cycle", cycle).toString(); + } + + public String toShortString() { + StringBuilder sb = new StringBuilder("["); + for (JavaPackage javaPackage : cycle) { + sb.append(javaPackage.name()).append(", "); + } + if (sb.length() > 1) { + sb.delete(sb.length() - 2, sb.length()); + } + sb.append("]"); + return sb.toString(); + } + +} 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; + } + +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java new file mode 100644 index 00000000..31959307 --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaEntity.java @@ -0,0 +1,44 @@ +package org.onlab.jdvue; + +import java.util.Objects; + +/** + * Abstraction of a Java source entity. + */ +public abstract class JavaEntity { + + private final String name; + + /** + * Creates a new Java source entity with the given name. + * + * @param name source entity name + */ + JavaEntity(String name) { + this.name = name; + } + + /** + * Returns the Java source entity name. + * + * @return source entity name + */ + public String name() { + return name; + } + + @Override + public boolean equals(Object o) { + if (o instanceof JavaEntity) { + JavaEntity that = (JavaEntity) o; + return getClass().equals(that.getClass()) && + Objects.equals(name, that.name); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java new file mode 100644 index 00000000..7bf4be16 --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaPackage.java @@ -0,0 +1,79 @@ +package org.onlab.jdvue; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Simple abstraction of a Java package for the purpose of tracking + * dependencies and requirements. + * + * @author Thomas Vachuska + */ +public class JavaPackage extends JavaEntity { + + private final Set<JavaSource> sources = new HashSet<>(); + private Set<JavaPackage> dependencies; + + /** + * Creates a new Java package. + * + * @param name java package file name + */ + JavaPackage(String name) { + super(name); + } + + /** + * Returns the set of sources contained in this Java package. + * + * @return set of Java sources + */ + public Set<JavaSource> getSources() { + return Collections.unmodifiableSet(sources); + } + + /** + * Adds the specified Java source to the package. Only possible if the + * Java package of the source is the same as this Java package. + * + * @param source Java source to be added + */ + void addSource(JavaSource source) { + if (source.getPackage().equals(this)) { + sources.add(source); + } + } + + /** + * Returns the set of packages directly required by this package. + * + * @return set of Java package dependencies + */ + Set<JavaPackage> getDependencies() { + return dependencies; + } + + /** + * Sets the set of resolved Java packages on which this package dependens. + * + * @param dependencies set of resolved Java packages + */ + void setDependencies(Set<JavaPackage> dependencies) { + if (this.dependencies == null) { + this.dependencies = Collections.unmodifiableSet(new HashSet<>(dependencies)); + } + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .add("sources", sources.size()) + .add("dependencies", (dependencies != null ? dependencies.size() : 0)) + .toString(); + } + +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java new file mode 100644 index 00000000..8919a13e --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/JavaSource.java @@ -0,0 +1,100 @@ +package org.onlab.jdvue; + +import java.util.*; + +import static com.google.common.base.MoreObjects.toStringHelper; + +/** + * Simple abstraction of a Java source file for the purpose of tracking + * dependencies and requirements. + * + * @author Thomas Vachuska + */ +public class JavaSource extends JavaEntity { + + private String path; + private JavaPackage javaPackage; + + private final Set<String> importNames = new HashSet<>(); + private Set<JavaEntity> imports; + + /** + * Creates a new Java source entity. + * + * @param name java source file name + * @param path source file path + */ + JavaSource(String name, String path) { + super(name); + this.path = path; + } + + /** + * Returns the Java package for this Java source. + * + * @return Java package + */ + public JavaPackage getPackage() { + return javaPackage; + } + + /** + * Sets the Java package for this Java source. + * + * @param javaPackage Java package + */ + void setPackage(JavaPackage javaPackage) { + if (this.javaPackage == null) { + this.javaPackage = javaPackage; + } + } + + /** + * Returns the set of resolved imports for this Java source + * + * @return set of imports + */ + public Set<JavaEntity> getImports() { + return imports; + } + + /** + * Sets the set of resolved imported Java entities for this source. + * + * @param imports set of resolved Java entities imported by this source + */ + void setImports(Set<JavaEntity> imports) { + if (this.imports == null) { + this.imports = Collections.unmodifiableSet(new HashSet<>(imports)); + } + } + + /** + * Adds a name of an imported, but unresolved, Java entity name. + * + * @param name name of an imported Java entity + */ + void addImportName(String name) { + importNames.add(name); + } + + /** + * Returns the set of imported, but unresolved, Java entity names. + * + * @return set of imported Java entity names + */ + Set<String> getImportNames() { + return importNames; + } + + @Override + public String toString() { + return toStringHelper(this) + .add("name", name()) + .add("javaPackage", (javaPackage != null ? javaPackage.name() : "")) + .add("importNames", importNames.size()) + .add("imports", (imports != null ? imports.size() : 0)) + .toString(); + } + +} diff --git a/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java new file mode 100644 index 00000000..2f77ef24 --- /dev/null +++ b/framework/src/onos/utils/jdvue/src/main/java/org/onlab/jdvue/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Utility to analyze Java package dependencies. + */ +package org.onlab.jdvue;
\ No newline at end of file |