
com.sun.enterprise.tools.visualizer.hk2.DotGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hk2-dependency-visualizer Show documentation
Show all versions of hk2-dependency-visualizer Show documentation
Tool to visualize the dependencies generated by HK2's dependency-verifier
/*
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.enterprise.tools.visualizer.hk2;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* reads a wires XML file generated by the dependency-verifier and outputs a dot
* file (Use GraphViz to create images
* from the dot file) that helps visualizing the wiring dependencies between
* packages. The tool also supports viewing the dependencies of only a subset of
* the packages.
*
* @author Sivakumar Thyagarajan
*/
public class DotGenerator {
private final static boolean DEBUG = false;
PrintStream wireOut = null;
GeneratorOptions options = null;
/**
* An internal class holding all the command line options
* supported by this DotGenerator
*
* @author Sivakumar Thyagarajan
*/
static class GeneratorOptions {
// Accept XML files generated by HK2 dependency-verifier
@Option(name = "-i", usage = "Input Wires XML file")
public String input = "wires.xml";
@Option(name = "-o", usage = "Output DOT file", required = true)
public String output;
@Option(name = "-m", usage = "Show only packages that contains the specified substring")
public String match = "";// By default, match all.
// receives other command line parameters than options
@Argument
public List arguments = new ArrayList();
}
/**
* A simple class representing all the information about a
* package that can be derived from the wires.xml
*
* @author Sivakumar Thyagarajan
*/
class PackageInfo {
String packageName, exportedBy = null;
String[] importedBy = null;
public PackageInfo(String packageName, String exportedBy,
String[] importedBy) {
this.packageName = packageName;
this.exportedBy = exportedBy;
this.importedBy = importedBy;
}
}
public DotGenerator(GeneratorOptions go) throws Exception {
this.options = go;
wireOut = new PrintStream(new FileOutputStream(this.options.output));
initXML();
generate();
}
private Document doc = null;
private void initXML() throws Exception {
File file = new File(this.options.input);
debug("file " + file);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
try {
dbf.setFeature(FEATURE, true);
} catch (ParserConfigurationException e) {
throw new IllegalStateException("ParserConfigurationException was thrown. The feature '"
+ FEATURE + "' is not supported by your XML processor.", e);
}
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(file);
doc.getDocumentElement().normalize();
}
private PackageInfo[] getPackageXML() throws IOException {
NodeList pkgLst = doc.getElementsByTagName("Package");
debug("Package count:" + pkgLst.getLength());
List pkgInfos = new ArrayList();
for (int i = 0; i < pkgLst.getLength(); i++) {
Node pkgNode = pkgLst.item(i);
if (pkgNode.getNodeType() == Node.ELEMENT_NODE) {
Element packageElement = (Element) pkgNode;
// exports
NodeList ExportersList = packageElement
.getElementsByTagName("Exporters");
Element exporterElt = (Element) ExportersList.item(0);
String exporter = ((Node) exporterElt.getChildNodes().item(0))
.getNodeValue().trim();
debug("Exporter : " + exporter);
// importers
NodeList importersList = packageElement
.getElementsByTagName("Importers");
Element importerElt = (Element) importersList.item(0);
String importers = ((Node) importerElt.getChildNodes().item(0))
.getNodeValue().trim();
debug("Importers : " + importers);
// Get package name and return PackageInfos
String pkgName = packageElement.getAttribute("name").trim();
debug("Package Name : " + pkgName);
PackageInfo pkgInfo = new PackageInfo(pkgName, exporter,
split(importers));
pkgInfos.add(pkgInfo);
}
}
return pkgInfos.toArray(new PackageInfo[] {});
}
private void generate() throws Exception {
generateDotStart();
PackageInfo[] pkgInfos = getPackageXML();
for (PackageInfo pkgInfo : pkgInfos) {
// Match if needed
String matchString = this.options.match.trim();
boolean matchNeeded = !matchString.isEmpty();
if (matchNeeded) {
if (pkgInfo.exportedBy.contains(matchString)) {
generateDotEdge(pkgInfo.importedBy, pkgInfo.exportedBy,
pkgInfo.packageName);
}
} else {
generateDotEdge(pkgInfo.importedBy, pkgInfo.exportedBy,
pkgInfo.packageName);
}
}
generateDotEnd();
}
private void debug(String s) {
if (DEBUG)
System.err.println(s);
}
private void debug(String text, String s) {
debug(text, new String[] { s });
}
private void debug(String text, String[] arr) {
StringBuffer sb = new StringBuffer(text);
for (String s : arr) {
sb.append(s).append(" , ");
}
debug(sb.toString());
}
public static void main(String[] args) throws Exception {
DotGenerator.GeneratorOptions options = new DotGenerator.GeneratorOptions();
CmdLineParser parser = new CmdLineParser(options);
try {
parser.parseArgument(args);
} catch (CmdLineException e) {
System.err.println(e.getMessage());
System.err.println("java -jar program-name.jar [options...] arguments...");
parser.printUsage(System.err);
return;
}
new DotGenerator(options);
}
// Generate the beginning of the dot file
private void generateDotStart() {
this.wireOut.println("digraph wiring {");
this.wireOut.println("node [color=grey, style=filled];");
this.wireOut.println("node [fontname=\"Verdana\", size=\"30,30\"];");
String date = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
DateFormat.SHORT).format(new Date());
StringBuffer footer = new StringBuffer();
footer.append("graph [ fontname = \"Arial\", fontsize = 26,style = \"bold\", ");
footer.append("label = \"\\nGlassFish v3 OSGi bundle wiring relationship diagram");
if (!this.options.match.trim().isEmpty()) {
footer.append("\\n Filter: " + this.options.match.trim()
+ " bundles");
}
footer.append("\\nSun Microsystems");
footer.append("\\n\\nDate: " + date + "\\n\", "
+ "ssize = \"30,60\" ];");
this.wireOut.println(footer.toString());
}
// Generate a Dot representation for each edge in the graph
private void generateDotEdge(String[] importedBy, String exportedBy,
String pkg) {
if (importedBy.length == 0)
return;
for (String s : importedBy) {
if (!s.equals(exportedBy)) { // remove self-loops for readability
this.wireOut.println("\"" + s + "\" -> \"" + exportedBy
+ "\" [label =\"" + pkg + "\"" + "]");
}
}
}
// End the dot file generation
private void generateDotEnd() {
this.wireOut.println("}");
}
// Utility class to split the importers representation (space separated)
//in wires.xml
private String[] split(String s) {
StringTokenizer st = new StringTokenizer(s);
List l = new ArrayList();
while (st.hasMoreTokens()) {
l.add(st.nextToken());
}
return l.toArray(new String[] {});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy