com.ibm.wala.util.viz.DotUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.ibm.wala.util Show documentation
Show all versions of com.ibm.wala.util Show documentation
T. J. Watson Libraries for Analysis
The newest version!
/*
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*/
package com.ibm.wala.util.viz;
import com.ibm.wala.util.WalaException;
import com.ibm.wala.util.collections.Iterator2Collection;
import com.ibm.wala.util.collections.Iterator2Iterable;
import com.ibm.wala.util.graph.Graph;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collection;
import org.jspecify.annotations.Nullable;
/** utilities for interfacing with DOT */
public class DotUtil {
/** possible output formats for dot */
public enum DotOutputType {
PS("ps"),
SVG("svg"),
PDF("pdf"),
EPS("eps");
public final String suffix;
DotOutputType(final String suffix) {
this.suffix = suffix;
}
}
private static DotOutputType outputType = DotOutputType.PDF;
private static int fontSize = 6;
private static final String fontColor = "black";
private static final String fontName = "Arial";
public static void setOutputType(DotOutputType outType) {
outputType = outType;
}
public static DotOutputType getOutputType() {
return outputType;
}
private static String outputTypeCmdLineParam() {
return "-T" + outputType.suffix;
}
/** Some versions of dot appear to croak on long labels. Reduce this if so. */
private static final int MAX_LABEL_LENGTH = Integer.MAX_VALUE;
/**
* @param the type of a graph node
*/
public static void dotify(
Graph g, NodeDecorator labels, String dotFile, String outputFile, String dotExe)
throws WalaException {
dotify(g, labels, null, dotFile, outputFile, dotExe);
}
/**
* @param the type of a graph node
*/
public static void dotify(
Graph g,
NodeDecorator labels,
@Nullable String title,
String dotFile,
String outputFile,
String dotExe)
throws WalaException {
if (g == null) {
throw new IllegalArgumentException("g is null");
}
File f = DotUtil.writeDotFile(g, labels, title, dotFile);
if (dotExe != null) {
spawnDot(dotExe, outputFile, f);
}
}
public static void spawnDot(String dotExe, String outputFile, File dotFile) throws WalaException {
if (dotFile == null) {
throw new IllegalArgumentException("dotFile is null");
}
String[] cmdarray = {
dotExe, outputTypeCmdLineParam(), "-o", outputFile, "-v", dotFile.getAbsolutePath()
};
System.out.println("spawning process " + Arrays.toString(cmdarray));
BufferedInputStream output = null;
BufferedInputStream error = null;
try {
Process p = Runtime.getRuntime().exec(cmdarray);
output = new BufferedInputStream(p.getInputStream());
error = new BufferedInputStream(p.getErrorStream());
boolean repeat = true;
while (repeat) {
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
e1.printStackTrace();
// just ignore and continue
}
if (output.available() > 0) {
byte[] data = new byte[output.available()];
int nRead = output.read(data);
System.err.println("read " + nRead + " bytes from output stream");
}
if (error.available() > 0) {
byte[] data = new byte[error.available()];
int nRead = error.read(data);
System.err.println("read " + nRead + " bytes from error stream");
}
try {
p.exitValue();
// if we get here, the process has terminated
repeat = false;
System.out.println("process terminated with exit code " + p.exitValue());
} catch (IllegalThreadStateException e) {
// this means the process has not yet terminated.
repeat = true;
}
}
} catch (IOException e) {
e.printStackTrace();
throw new WalaException("IOException in " + DotUtil.class);
} finally {
if (output != null) {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (error != null) {
try {
error.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static File writeDotFile(
Graph g, NodeDecorator labels, @Nullable String title, String dotfile)
throws WalaException {
if (g == null) {
throw new IllegalArgumentException("g is null");
}
StringBuilder dotStringBuffer = dotOutput(g, labels, title);
// retrieve the filename parameter to this component, a String
if (dotfile == null) {
throw new WalaException("internal error: null filename parameter");
}
try {
File f = new File(dotfile);
try (Writer fw = Files.newBufferedWriter(f.toPath(), StandardCharsets.UTF_8)) {
fw.write(dotStringBuffer.toString());
}
return f;
} catch (Exception e) {
throw new WalaException("Error writing dot file " + dotfile, e);
}
}
/**
* @return StringBuffer holding dot output representing G
*/
public static StringBuilder dotOutput(
Graph g, NodeDecorator labels, @Nullable String title) throws WalaException {
StringBuilder result = new StringBuilder("digraph \"DirectedGraph\" {\n");
if (title != null) {
result
.append("graph [label = \"")
.append(title)
.append("\", labelloc=t, concentrate = true];");
} else {
result.append("graph [concentrate = true];");
}
String rankdir = getRankDir();
if (rankdir != null) {
result.append("rankdir=").append(rankdir).append(';');
}
String fontsizeStr = "fontsize=" + fontSize;
String fontcolorStr = ",fontcolor=" + fontColor;
String fontnameStr = ",fontname=" + fontName;
result.append("center=true;");
result.append(fontsizeStr);
result.append(";node [ color=blue,shape=\"box\"");
result.append(fontsizeStr);
result.append(fontcolorStr);
result.append(fontnameStr);
result.append("];edge [ color=black,");
result.append(fontsizeStr);
result.append(fontcolorStr);
result.append(fontnameStr);
result.append("]; \n");
Collection dotNodes = computeDotNodes(g);
outputNodes(labels, result, dotNodes);
for (T n : g) {
for (T s : Iterator2Iterable.make(g.getSuccNodes(n))) {
result.append(' ');
result.append(getPort(n, labels));
result.append(" -> ");
result.append(getPort(s, labels));
result.append(" \n");
}
}
result.append("\n}");
return result;
}
private static void outputNodes(
NodeDecorator labels, StringBuilder result, Collection dotNodes) throws WalaException {
for (T t : dotNodes) {
outputNode(labels, result, t);
}
}
private static void outputNode(NodeDecorator labels, StringBuilder result, T n)
throws WalaException {
result.append(" ");
result.append('\"');
result.append(getLabel(n, labels));
result.append('\"');
result.append(decorateNode(n, labels));
}
/** Compute the nodes to visualize */
private static Collection computeDotNodes(Graph g) {
return Iterator2Collection.toSet(g.iterator());
}
private static @Nullable String getRankDir() {
return null;
}
/**
* @param n node to decorate
* @param d decorating master
*/
private static String decorateNode(T n, NodeDecorator d) throws WalaException {
return " [ label=\"" + getLabel(n, d) + "\"]\n";
}
private static String getLabel(T n, NodeDecorator d) throws WalaException {
String result;
if (d == null) {
result = n.toString();
} else {
result = d.getLabel(n);
result = result == null ? n.toString() : result;
}
if (result.length() >= MAX_LABEL_LENGTH) {
result = result.substring(0, MAX_LABEL_LENGTH - 3) + "...";
}
return result;
}
private static String getPort(T n, NodeDecorator d) throws WalaException {
return '"' + getLabel(n, d) + '"';
}
public static int getFontSize() {
return fontSize;
}
public static void setFontSize(int fontSize) {
DotUtil.fontSize = fontSize;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy