
org.dstadler.commons.graphviz.DotUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-dost Show documentation
Show all versions of commons-dost Show documentation
Common utilities I find useful in many of my projects.
The newest version!
package org.dstadler.commons.graphviz;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
/**
* Simple utility methods to run the dot-tool from Graphviz on a file.
*/
public class DotUtils {
public static String DOT_EXE = SystemUtils.IS_OS_WINDOWS ? "C:\\cygwin\\bin\\dot.exe" : "/usr/bin/dot";
private final static String FOOTER = "}\n";
/**
* Write out the string and a newline
*
* @param writer The writer for the .dot-file
* @param string The text to write
* @throws IOException if writing to the Writer fails
*/
public static void writeln(final Writer writer, final String string) throws IOException {
writeln(writer, string, 0);
}
/**
* Write out the string and a newline, appending a number of tabs to
* properly indent the resulting text-file.
*
* @param writer The writer for the .dot-file
* @param string The text to write
* @param indentLevel How much to indent the line
* @throws IOException if writing to the Writer fails
*/
public static void writeln(final Writer writer, final String string, int indentLevel) throws IOException {
writer.write(StringUtils.repeat("\t", indentLevel) + string);
writer.write("\n");
}
/**
* Write the header structure.
*
* @param writer A writer where the header is written to.
* @param dpi The resulting resolution, can be 0 for using the default DPI-setting of dot
* @param rankDir The direction of the graph, can be null
* @param id The id of the graph, cannot be null, needs to start with a alphabetical character, can contain numbers, alphabetic characters and underscore only.
* @param attribLines Additional attributes, can be null
*
* @throws IOException if writing to the Writer fails
*/
public static void writeHeader(Writer writer, int dpi, String rankDir, String id, List attribLines) throws IOException {
// Default settings
if (attribLines == null) {
attribLines = new ArrayList<>();
} else {
attribLines = new ArrayList<>(attribLines);
}
attribLines.add("node [shape=box];");
// add ...
// DPI and Rankdir
StringBuilder header = new StringBuilder("digraph " + id + " {\n");
if (dpi > 0) {
header.append("dpi=").append(dpi).append(";\n");
}
header.append("rankdir=").append(StringUtils.isNotBlank(rankDir) ? rankDir : "LR").append(";\n");
// Additional lines
for (String line : attribLines) {
line = line.trim();
header.append(line).append(line.endsWith(";") ? "\n" : ";\n");
}
DotUtils.writeln(writer, header.toString());
}
/**
* Closes the graph-markup with the necessary closing statements.
*
* @param writer A writer where the footer is written to.
*
* @throws IOException if writing to the Writer fails
*/
public static void writeFooter(Writer writer) throws IOException {
writeln(writer, FOOTER);
}
/**
* Call graphviz-dot to convert the .dot-file to a rendered graph.
*
* The file extension of the specified result file is being used as the filetype
* of the rendering.
*
* @param dotfile The dot {@code File} used for the graph generation
* @param resultfile The {@code File} to which should be written
*
* @throws IOException if writing the resulting graph fails or other I/O
* problems occur
*/
public static void renderGraph(File dotfile, File resultfile) throws IOException {
// call graphviz-dot via commons-exec
CommandLine cmdLine = new CommandLine(DOT_EXE);
cmdLine.addArgument("-T" + StringUtils.substringAfterLast(resultfile.getAbsolutePath(), "."));
cmdLine.addArgument(dotfile.getAbsolutePath());
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(0);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
try {
try (FileOutputStream out2 = new FileOutputStream(resultfile)) {
executor.setStreamHandler(new PumpStreamHandler(out2, System.err));
int exitValue = executor.execute(cmdLine);
if(exitValue != 0) {
throw new IOException("Could not convert graph to dot, had exit value: " + exitValue + "!");
}
}
} catch (IOException e) {
// if something went wrong the file should not be left behind...
if(!resultfile.delete()) {
System.out.println("Could not delete file " + resultfile);
}
throw e;
}
}
/**
* Verify if dot can be started and print out the version to stdout.
*
* @return True if "dot -V" ran successfully, false otherwise
*
* @throws IOException If running dot fails.
*/
public static boolean checkDot() throws IOException {
// call graphviz-dot via commons-exec
CommandLine cmdLine = new CommandLine(DOT_EXE);
cmdLine.addArgument("-V");
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue(0);
ExecuteWatchdog watchdog = new ExecuteWatchdog(60000);
executor.setWatchdog(watchdog);
executor.setStreamHandler(new PumpStreamHandler(System.out, System.err));
int exitValue = executor.execute(cmdLine);
if(exitValue != 0) {
System.err.println("Could not run '" + DOT_EXE + "', had exit value: " + exitValue + "!");
return false;
}
return true;
}
/**
* Allows to define where the exe-file for dot can be found.
*
* @param dotExe The full pathname of the dot-executable.
*/
public static void setDotExe(String dotExe) {
DOT_EXE = dotExe;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy