package schemacrawler.tools.integration.graph;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import sf.util.Utility;
final class GraphGenerator
{
private static final Logger LOGGER = Logger.getLogger(GraphGenerator.class
.getName());
private final File dotFile;
private final String graphOutputFormat;
private final File diagramFile;
GraphGenerator(final File dotFile,
final String outputFormat,
final File diagramOutputFile)
throws IOException
{
if (dotFile == null || dotFile.isDirectory() || !dotFile.exists()
|| !dotFile.canRead())
{
throw new IOException("Cannot read the input DOT file, " + dotFile);
}
this.dotFile = dotFile;
graphOutputFormat = determineGraphOutputFormat(outputFormat);
diagramFile = determineDiagramFile(diagramOutputFile);
}
void generateDiagram()
throws IOException
{
final String graphGenerator = System
.getProperty("schemacrawler.graph_generator", "dot");
final String[] command = new String[] {
graphGenerator,
"-q",
"-T" + graphOutputFormat,
"-o",
diagramFile.getAbsolutePath(),
dotFile.getAbsolutePath()
};
LOGGER.log(Level.CONFIG, "Executing: " + Arrays.toString(command));
final ExecutorService threadPool = Executors.newFixedThreadPool(2);
try
{
final class StreamReader
implements Callable<String>
{
private final InputStream in;
private StreamReader(final InputStream in)
{
this.in = in;
}
@Override
public String call()
throws Exception
{
final Reader reader = new BufferedReader(new InputStreamReader(in));
return Utility.readFully(reader);
}
}
final Process process = new ProcessBuilder(command).start();
final FutureTask<String> inReaderTask = new FutureTask<String>(new StreamReader(process
.getInputStream()));
threadPool.execute(inReaderTask);
final FutureTask<String> errReaderTask = new FutureTask<String>(new StreamReader(process
.getErrorStream()));
threadPool.execute(errReaderTask);
final int exitCode = process.waitFor();
final String processOutput = inReaderTask.get();
if (!Utility.isBlank(processOutput))
{
LOGGER.log(Level.INFO, processOutput);
}
final String processError = errReaderTask.get();
if (exitCode != 0)
{
throw new IOException(String.format("Process returned exit code %d%n%s",
exitCode,
processError));
}
if (!Utility.isBlank(processError))
{
LOGGER.log(Level.WARNING, processError);
}
}
catch (final SecurityException e)
{
throw new IOException(e.getMessage(), e);
}
catch (final ExecutionException e)
{
throw new IOException(e.getMessage(), e);
}
catch (final InterruptedException e)
{
throw new IOException(e.getMessage(), e);
}
finally
{
threadPool.shutdown();
}
}
private File determineDiagramFile(final File diagramOutputFile)
{
File diagramFile;
if (diagramOutputFile == null)
{
diagramFile = new File(".", "schemacrawler." + UUID.randomUUID() + "."
+ graphOutputFormat);
}
else
{
diagramFile = diagramOutputFile;
}
return diagramFile;
}
private String determineGraphOutputFormat(final String outputFormat)
{
String graphOutputFormat = outputFormat;
final List<String> outputFormats = Arrays.asList("canon",
"cmap",
"cmapx",
"cmapx_np",
"dot",
"eps",
"fig",
"gd",
"gd2",
"gif",
"gv",
"imap",
"imap_np",
"ismap",
"jpe",
"jpeg",
"jpg",
"pdf",
"plain",
"plain-ext",
"png",
"ps",
"ps2",
"svg",
"svgz",
"tk",
"vml",
"vmlz",
"vrml",
"wbmp",
"xdot");
if (Utility.isBlank(graphOutputFormat)
|| !outputFormats.contains(graphOutputFormat))
{
graphOutputFormat = "png";
}
return graphOutputFormat;
}
}