All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dstadler.commons.graphviz.DotUtils Maven / Gradle / Ivy

There is a newer version: 1.3.4
Show newest version
package org.dstadler.commons.graphviz;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteException;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

/**
 * Simple utility methods to run the dot-tool from Graphviz on a file.
 *
 * @author dominik.stadler
 *
 */
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
     * @param string
     * @throws IOException
     */
    public static void writeln(final Writer writer, final String string) throws IOException {
        writeln(writer, string, 0);
    }

    /**
	 * Write out the string and a newline
	 *
	 * @param writer
	 * @param string
	 * @param indentLevel
     * @throws IOException
	 */
	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
        String header = "digraph " + id + " {\n";
        if (dpi > 0) {
            header += "dpi=" + dpi + ";\n";
        }
        header += "rankdir=" + (StringUtils.isNotBlank(rankdir) ? rankdir : "LR") + ";\n";

        // Additional lines
        for (String line : attribLines) {
            line = line.trim();
            header += line + (line.endsWith(";") ? "\n" : ";\n");
        }
        DotUtils.writeln(writer, header);
    }

    /**
     * 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
	 */
	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...
			resultfile.delete();

			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 ExecuteException
	 * @throws IOException
	 */
	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;
	}

	public static void setDotExe(String dotExe) {
		DOT_EXE = dotExe;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy