• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

LearnLib / automatalib / 16696482329

02 Aug 2025 06:25PM UTC coverage: 92.155% (+0.04%) from 92.114%
16696482329

push

github

mtf90
try alternative path computation

16587 of 17999 relevant lines covered (92.16%)

1.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.58
/visualization/dot-visualizer/src/main/java/net/automatalib/visualization/dot/DOT.java
1
/* Copyright (C) 2013-2025 TU Dortmund University
2
 * This file is part of AutomataLib <https://automatalib.net>.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.automatalib.visualization.dot;
17

18
import java.awt.Desktop;
19
import java.awt.image.BufferedImage;
20
import java.io.ByteArrayInputStream;
21
import java.io.ByteArrayOutputStream;
22
import java.io.File;
23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.io.OutputStream;
26
import java.io.Reader;
27
import java.io.StringReader;
28
import java.nio.file.FileSystems;
29
import java.nio.file.Path;
30
import java.util.Arrays;
31
import java.util.List;
32

33
import javax.imageio.ImageIO;
34

35
import net.automatalib.common.setting.AutomataLibProperty;
36
import net.automatalib.common.setting.AutomataLibSettings;
37
import net.automatalib.common.util.IOUtil;
38
import net.automatalib.common.util.Pair;
39
import net.automatalib.common.util.process.ProcessUtil;
40
import net.automatalib.visualization.dot.DOTMultiDialog.ThrowableExtractor;
41
import org.slf4j.Logger;
42
import org.slf4j.LoggerFactory;
43

44
/**
45
 * Utility class to simplify operating the GraphVIZ "dot" utility. Please note that all the provided methods require
46
 * GraphVIZ to be installed on the system, and that the "dot" binary resides in the execution path.
47
 */
48
public final class DOT {
49

50
    private static final Logger LOGGER = LoggerFactory.getLogger(DOT.class);
2✔
51

52
    private static String dotExe;
53

54
    static {
55
        final AutomataLibSettings settings = AutomataLibSettings.getInstance();
2✔
56

57
        final String dotExePath = settings.getProperty(AutomataLibProperty.DOT_EXE_DIR);
2✔
58
        final String dotExeName = settings.getProperty(AutomataLibProperty.DOT_EXE_NAME, "dot");
2✔
59

60
        String dotExe = dotExeName;
2✔
61
        if (dotExePath != null) {
2✔
62
            Path dotBasePath = FileSystems.getDefault().getPath(dotExePath);
×
63
            Path resolvedDotPath = dotBasePath.resolve(dotExeName);
×
64
            dotExe = resolvedDotPath.toString();
×
65
        }
66

67
        DOT.dotExe = dotExe;
2✔
68
    }
2✔
69

70
    private DOT() {}
71

72
    /**
73
     * Explicitly sets the path to the DOT utility executable.
74
     *
75
     * @param dotExe
76
     *         the path to the DOT utility executable
77
     */
78
    public static void setDotExe(String dotExe) {
79
        DOT.dotExe = dotExe;
×
80
    }
×
81

82
    /**
83
     * Checks whether the DOT utility can be successfully invoked.
84
     *
85
     * @return whether the DOT utility can be successfully invoked
86
     */
87
    public static boolean checkUsable() {
88
        try {
89
            final String[] dotCheck = buildRawDOTCommand("-V");
2✔
90
            return ProcessUtil.invokeProcess(dotCheck) == 0;
2✔
91
        } catch (IOException | InterruptedException ex) {
×
92
            LOGGER.error("Error executing dot", ex);
×
93
        }
94
        return false;
×
95
    }
96

97
    /**
98
     * Invokes the DOT utility on a file. Convenience method for {@link #runDOT(Reader, String, String...)}.
99
     *
100
     * @param dotFile
101
     *         the file from which the GraphVIZ description is obtained
102
     * @param format
103
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
104
     * @param additionalOpts
105
     *         additional parameters passed to the dot invocation
106
     *
107
     * @return an input stream from which the image data can be read
108
     *
109
     * @throws IOException
110
     *         if reading from the file or the call to the DOT utility fails.
111
     * @throws InterruptedException
112
     *         if the process is interrupted prior to finishing
113
     */
114
    public static InputStream runDOT(File dotFile, String format, String... additionalOpts)
115
            throws IOException, InterruptedException {
116
        return runDOT(IOUtil.asBufferedUTF8Reader(dotFile), format, additionalOpts);
×
117
    }
118

119
    /**
120
     * Invokes the GraphVIZ DOT utility for rendering graphs.
121
     *
122
     * @param r
123
     *         the reader from which the GraphVIZ description is obtained
124
     * @param format
125
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
126
     * @param additionalOpts
127
     *         additional parameters passed to the dot invocation
128
     *
129
     * @return an input stream from which the image data can be read
130
     *
131
     * @throws IOException
132
     *         if reading from the reader or the call to the DOT utility fails.
133
     * @throws InterruptedException
134
     *         if the process is interrupted prior to finishing
135
     */
136
    public static InputStream runDOT(Reader r, String format, String... additionalOpts)
137
            throws IOException, InterruptedException {
138
        final String[] dotCommand = buildDOTCommand(format, additionalOpts);
2✔
139

140
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
2✔
141
            ProcessUtil.invokeProcess(Arrays.asList(dotCommand), r, baos, OutputStream.nullOutputStream());
2✔
142
            return new ByteArrayInputStream(baos.toByteArray());
2✔
143
        }
144
    }
145

146
    /**
147
     * Invokes the DOT utility on a string. Convenience method for {@link #runDOT(Reader, String, String...)}.
148
     *
149
     * @param dotText
150
     *         the string from which the GraphVIZ description is obtained
151
     * @param format
152
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
153
     * @param additionalOpts
154
     *         additional parameters passed to the dot invocation
155
     *
156
     * @return an input stream from which the image data can be read
157
     *
158
     * @throws IOException
159
     *         if the call to the DOT utility fails.
160
     * @throws InterruptedException
161
     *         if the process is interrupted prior to finishing
162
     */
163
    public static InputStream runDOT(String dotText, String format, String... additionalOpts)
164
            throws IOException, InterruptedException {
165
        try (StringReader sr = new StringReader(dotText)) {
×
166
            return runDOT(sr, format, additionalOpts);
×
167
        }
168
    }
169

170
    /**
171
     * Invokes the DOT utility on a file, producing an output file. Convenience method for
172
     * {@link #runDOT(Reader, String, File)}.
173
     *
174
     * @param dotFile
175
     *         the file from which the GraphVIZ description is read
176
     * @param format
177
     *         the output format to produce
178
     * @param out
179
     *         the file to which the output is written
180
     *
181
     * @throws IOException
182
     *         if reading from the file, the call to the DOT utility, or writing to the file fails.
183
     * @throws InterruptedException
184
     *         if the process is interrupted prior to finishing
185
     */
186
    public static void runDOT(File dotFile, String format, File out) throws IOException, InterruptedException {
187
        runDOT(IOUtil.asBufferedUTF8Reader(dotFile), format, out);
2✔
188
    }
2✔
189

190
    /**
191
     * Invokes the GraphVIZ DOT utility for rendering graphs, writing output to the specified file.
192
     *
193
     * @param r
194
     *         the reader from which the GraphVIZ description is read
195
     * @param format
196
     *         the output format to produce
197
     * @param out
198
     *         the file to which the output is written.
199
     *
200
     * @throws IOException
201
     *         if reading from the reader, the call to the DOT utility, or writing to the file fails.
202
     * @throws InterruptedException
203
     *         if the process is interrupted prior to finishing
204
     */
205
    public static void runDOT(Reader r, String format, File out) throws IOException, InterruptedException {
206
        final String[] dotCommand = buildDOTCommand(format, "-o" + out.getAbsolutePath());
2✔
207

208
        ProcessUtil.invokeProcess(dotCommand, r, LOGGER::debug, LOGGER::warn);
2✔
209
    }
2✔
210

211
    /**
212
     * Invokes the DOT utility on a string, producing an output file. Convenience method for
213
     * {@link #runDOT(Reader, String, File)}.
214
     *
215
     * @param dotText
216
     *         the string from which the GraphVIZ description is read
217
     * @param format
218
     *         the output format to produce
219
     * @param out
220
     *         the file to which the output is written
221
     *
222
     * @throws IOException
223
     *         if the call to the DOT utility or writing to the file fails.
224
     * @throws InterruptedException
225
     *         if the process is interrupted prior to finishing
226
     */
227
    public static void runDOT(String dotText, String format, File out) throws IOException, InterruptedException {
228
        runDOT(new StringReader(dotText), format, out);
×
229
    }
×
230

231
    /**
232
     * Renders a GraphVIZ description from a file, using an external program for displaying. Convenience method for
233
     * {@link #renderDOTExternal(Reader, String)}.
234
     *
235
     * @param dotFile
236
     *         the file from which the GraphVIZ description is read
237
     * @param format
238
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
239
     *
240
     * @throws IOException
241
     *         if reading from the file or the call to the DOT utility fails.
242
     * @throws InterruptedException
243
     *         if the process is interrupted prior to finishing
244
     */
245
    public static void renderDOTExternal(File dotFile, String format) throws IOException, InterruptedException {
246
        renderDOTExternal(IOUtil.asBufferedUTF8Reader(dotFile), format);
×
247
    }
×
248

249
    /**
250
     * Renders a GraphVIZ description, using an external program for displaying. The program is determined by the
251
     * system's file type associations, using the {@link Desktop#open(File)} method.
252
     *
253
     * @param r
254
     *         the reader from which the GraphVIZ description is read
255
     * @param format
256
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
257
     *
258
     * @throws IOException
259
     *         if reading from the reader or the call to the DOT utility fails.
260
     * @throws InterruptedException
261
     *         if the process is interrupted prior to finishing
262
     */
263
    public static void renderDOTExternal(Reader r, String format) throws IOException, InterruptedException {
264
        final File image = File.createTempFile("dot", format);
×
265
        runDOT(r, format, image);
×
266
        Desktop.getDesktop().open(image);
×
267
    }
×
268

269
    /**
270
     * Renders a GraphVIZ description from a string, using an external program for displaying. Convenience method for
271
     * {@link #renderDOTExternal(Reader, String)}.
272
     *
273
     * @param dotText
274
     *         the string from which the GraphVIZ description is read.
275
     * @param format
276
     *         the output format, as understood by the dot utility, e.g., png, ps, etc.
277
     *
278
     * @throws IOException
279
     *         if the call to the DOT utility fails.
280
     * @throws InterruptedException
281
     *         if the process is interrupted prior to finishing
282
     */
283
    public static void renderDOTExternal(String dotText, String format) throws IOException, InterruptedException {
284
        renderDOTExternal(new StringReader(dotText), format);
×
285
    }
×
286

287
    /**
288
     * Renders a GraphVIZ description from a {@link File} and displays it in a Swing window. Convenience method for
289
     * {@link #renderDOT(Reader, boolean)}.
290
     *
291
     * @param dotFile
292
     *         the file from which the description is obtained
293
     * @param modal
294
     *         whether the dialog should be modal
295
     *
296
     * @throws IOException
297
     *         if reading from the file or the call to the DOT utility fails.
298
     * @throws InterruptedException
299
     *         if the process is interrupted prior to finishing
300
     */
301
    public static void renderDOT(File dotFile, boolean modal) throws IOException, InterruptedException {
302
        renderDOT(IOUtil.asBufferedUTF8Reader(dotFile), modal);
×
303
    }
×
304

305
    /**
306
     * Renders a GraphVIZ description from a {@link Reader} and displays it in a Swing window. Convenience method for
307
     * {@link #renderDOT(String, boolean)}.
308
     *
309
     * @param r
310
     *         the reader from which the description is obtained
311
     * @param modal
312
     *         whether the dialog should be modal
313
     *
314
     * @throws IOException
315
     *         if reading from the reader or the call to the DOT utility fails.
316
     * @throws InterruptedException
317
     *         if the process is interrupted prior to finishing
318
     */
319
    public static void renderDOT(Reader r, boolean modal) throws IOException, InterruptedException {
320
        renderDOT(IOUtil.toString(r), modal);
×
321
    }
×
322

323
    /**
324
     * Renders a GraphVIZ description and displays it in a Swing window.
325
     *
326
     * @param dotText
327
     *         the string from which the description is obtained
328
     * @param modal
329
     *         whether the dialog should be modal
330
     *
331
     * @throws IOException
332
     *         if the call to the DOT utility fails.
333
     * @throws InterruptedException
334
     *         if the process is interrupted prior to finishing
335
     */
336
    public static void renderDOT(String dotText, boolean modal) throws IOException, InterruptedException {
337
        new DOTDialog(dotText, modal);
2✔
338
    }
2✔
339

340
    /**
341
     * Renders multiple (named) GraphVIZ descriptions from {@link File}s and displays them in a Swing window.
342
     * Convenience method for {@link #renderDOTStrings(List, boolean)}.
343
     *
344
     * @param files
345
     *         the file from which the description is obtained. The first element of the {@link Pair} should contain the
346
     *         name, the second element should contain the DOT file.
347
     * @param modal
348
     *         whether the dialog should be modal
349
     *
350
     * @throws IOException
351
     *         if reading from the files or the calls to the DOT utility fail.
352
     * @throws InterruptedException
353
     *         if the process is interrupted prior to finishing
354
     */
355
    public static void renderDOTFiles(List<Pair<String, File>> files, boolean modal)
356
            throws IOException, InterruptedException {
357
        renderDOTInternal(files, modal, f -> IOUtil.toString(IOUtil.asBufferedUTF8Reader(f)));
×
358
    }
×
359

360
    /**
361
     * Renders multiple (named) GraphVIZ descriptions from {@link Reader}s and displays them in a Swing window.
362
     * Convenience method for {@link #renderDOTStrings(List, boolean)}.
363
     *
364
     * @param readers
365
     *         the readers from which the description is obtained. The first element of the {@link Pair} should contain
366
     *         the name, the second element should contain a reader for the DOT definition.
367
     * @param modal
368
     *         whether the dialog should be modal
369
     *
370
     * @throws IOException
371
     *         if reading from the readers or the calls to the DOT utility fail.
372
     * @throws InterruptedException
373
     *         if the process is interrupted prior to finishing
374
     */
375
    public static void renderDOTReaders(List<Pair<String, Reader>> readers, boolean modal)
376
            throws IOException, InterruptedException {
377
        renderDOTInternal(readers, modal, IOUtil::toString);
2✔
378
    }
2✔
379

380
    /**
381
     * Renders multiple (named) GraphVIZ descriptions and displays them in a Swing window.
382
     *
383
     * @param dotTexts
384
     *         the strings from which the description is obtained. The first element of the {@link Pair} should contain
385
     *         the name, the second element should contain the DOT code.
386
     * @param modal
387
     *         whether the dialog should be modal
388
     *
389
     * @throws IOException
390
     *         if the calls to the DOT utility fail.
391
     * @throws InterruptedException
392
     *         if the process is interrupted prior to finishing
393
     */
394
    public static void renderDOTStrings(List<Pair<String, String>> dotTexts, boolean modal)
395
            throws IOException, InterruptedException {
396
        renderDOTInternal(dotTexts, modal, s -> s);
2✔
397
    }
2✔
398

399
    private static <I> void renderDOTInternal(List<Pair<String, I>> dots,
400
                                              boolean modal,
401
                                              ThrowableExtractor<I, String> extractor)
402
            throws IOException, InterruptedException {
403
        new DOTMultiDialog<>(dots, modal, extractor);
2✔
404
    }
2✔
405

406
    /**
407
     * Reads a DOT description from a file and returns the PNG rendering result as a {@link BufferedImage}.
408
     *
409
     * @param dotFile
410
     *         the file containing the DOT description
411
     *
412
     * @return the rendering result
413
     *
414
     * @throws IOException
415
     *         if reading from the file or the call to the DOT utility fails.
416
     * @throws InterruptedException
417
     *         if the process is interrupted prior to finishing
418
     */
419
    public static BufferedImage renderDOTImage(File dotFile) throws IOException, InterruptedException {
420
        return renderDOTImage(IOUtil.asBufferedUTF8Reader(dotFile));
×
421
    }
422

423
    /**
424
     * Reads a DOT description from a reader and returns the PNG rendering result as a {@link BufferedImage}.
425
     *
426
     * @param dotReader
427
     *         the reader from which to read the description
428
     *
429
     * @return the rendering result
430
     *
431
     * @throws IOException
432
     *         if reading from the reader or the call to the DOT utility fails.
433
     * @throws InterruptedException
434
     *         if the process is interrupted prior to finishing
435
     */
436
    public static BufferedImage renderDOTImage(Reader dotReader) throws IOException, InterruptedException {
437
        try (InputStream pngIs = runDOT(dotReader, "png")) {
2✔
438
            return ImageIO.read(pngIs);
2✔
439
        }
440
    }
441

442
    /**
443
     * Reads a DOT description from a string and returns the PNG rendering result as a {@link BufferedImage}.
444
     *
445
     * @param dotText
446
     *         the DOT description
447
     *
448
     * @return the rendering result
449
     *
450
     * @throws IOException
451
     *         if the call to the DOT utility fails.
452
     * @throws InterruptedException
453
     *         if the process is interrupted prior to finishing
454
     */
455
    public static BufferedImage renderDOTImage(String dotText) throws IOException, InterruptedException {
456
        return renderDOTImage(new StringReader(dotText));
2✔
457
    }
458

459
    private static String[] buildRawDOTCommand(String... opts) {
460
        String[] dotArgs = new String[1 + opts.length];
2✔
461
        dotArgs[0] = dotExe;
2✔
462
        System.arraycopy(opts, 0, dotArgs, 1, opts.length);
2✔
463

464
        return dotArgs;
2✔
465
    }
466

467
    private static String[] buildDOTCommand(String format, String... additionalOpts) {
468
        String[] dotArgs = new String[1 + additionalOpts.length];
2✔
469
        dotArgs[0] = "-T" + format;
2✔
470
        System.arraycopy(additionalOpts, 0, dotArgs, 1, additionalOpts.length);
2✔
471

472
        return buildRawDOTCommand(dotArgs);
2✔
473
    }
474

475
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc