aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store-dse-visualization/src
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-06 19:05:10 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-09-06 19:05:10 +0200
commit895b26df7a806a2136c2f7a46d56b542326e561f (patch)
tree52915b0bdb44a3b5d4c150050e89d987383e17e0 /subprojects/store-dse-visualization/src
parentrefactor: rename store-dse-visualization (diff)
downloadrefinery-895b26df7a806a2136c2f7a46d56b542326e561f.tar.gz
refinery-895b26df7a806a2136c2f7a46d56b542326e561f.tar.zst
refinery-895b26df7a806a2136c2f7a46d56b542326e561f.zip
feat(dse): transformation rule builder
Diffstat (limited to 'subprojects/store-dse-visualization/src')
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java32
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java16
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java22
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java26
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java60
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java387
-rw-r--r--subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java55
7 files changed, 598 insertions, 0 deletions
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
new file mode 100644
index 00000000..ae87d8ac
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerAdapter.java
@@ -0,0 +1,32 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.map.Version;
10import tools.refinery.store.tuple.Tuple;
11import tools.refinery.visualization.internal.ModelVisualizerBuilderImpl;
12
13import java.util.Collection;
14
15public interface ModelVisualizerAdapter extends ModelAdapter {
16
17 ModelVisualizerStoreAdapter getStoreAdapter();
18 static ModelVisualizerBuilder builder() {
19 return new ModelVisualizerBuilderImpl();
20 }
21
22 public void addTransition(Version from, Version to, String action);
23
24
25 public void addTransition(Version from, Version to, String action, Tuple activation);
26 public void addState(Version state);
27 public void addState(Version state, Collection<Double> fitness);
28 public void addState(Version state, String label);
29 public void addSolution(Version state);
30 public void visualize();
31
32}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
new file mode 100644
index 00000000..592f5fcf
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerBuilder.java
@@ -0,0 +1,16 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization;
7
8import tools.refinery.store.adapter.ModelAdapterBuilder;
9import tools.refinery.visualization.internal.FileFormat;
10
11public interface ModelVisualizerBuilder extends ModelAdapterBuilder {
12 ModelVisualizerBuilder withOutputpath(String outputpath);
13 ModelVisualizerBuilder withFormat(FileFormat format);
14 ModelVisualizerBuilder saveDesignSpace();
15 ModelVisualizerBuilder saveStates();
16}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java
new file mode 100644
index 00000000..46663b2a
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/ModelVisualizerStoreAdapter.java
@@ -0,0 +1,22 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization;
7
8import tools.refinery.store.adapter.ModelStoreAdapter;
9import tools.refinery.visualization.internal.FileFormat;
10
11import java.util.Set;
12
13public interface ModelVisualizerStoreAdapter extends ModelStoreAdapter {
14
15 String getOutputPath();
16
17 boolean isRenderDesignSpace();
18
19 boolean isRenderStates();
20
21 Set<FileFormat> getFormats();
22}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java
new file mode 100644
index 00000000..c5dffeb2
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/FileFormat.java
@@ -0,0 +1,26 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization.internal;
7
8public enum FileFormat {
9 BMP("bmp"),
10 DOT("dot"),
11 JPEG("jpg"),
12 PDF("pdf"),
13 PLAIN("plain"),
14 PNG("png"),
15 SVG("svg");
16
17 private final String format;
18
19 FileFormat(String format) {
20 this.format = format;
21 }
22
23 public String getFormat() {
24 return format;
25 }
26}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java
new file mode 100644
index 00000000..04be22d6
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizeStoreAdapterImpl.java
@@ -0,0 +1,60 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization.internal;
7
8import tools.refinery.store.adapter.ModelAdapter;
9import tools.refinery.store.model.Model;
10import tools.refinery.store.model.ModelStore;
11import tools.refinery.visualization.ModelVisualizerStoreAdapter;
12
13import java.util.Set;
14
15public class ModelVisualizeStoreAdapterImpl implements ModelVisualizerStoreAdapter {
16 private final ModelStore store;
17 private final String outputPath;
18 private final boolean renderDesignSpace;
19 private final boolean renderStates;
20 private final Set<FileFormat> formats;
21
22 public ModelVisualizeStoreAdapterImpl(ModelStore store, String outputPath, Set<FileFormat> formats,
23 boolean renderDesignSpace, boolean renderStates) {
24 this.store = store;
25 this.outputPath = outputPath;
26 this.formats = formats;
27 this.renderDesignSpace = renderDesignSpace;
28 this.renderStates = renderStates;
29 }
30
31 @Override
32 public ModelStore getStore() {
33 return store;
34 }
35
36 @Override
37 public ModelAdapter createModelAdapter(Model model) {
38 return new ModelVisualizerAdapterImpl(model, this);
39 }
40
41 @Override
42 public String getOutputPath() {
43 return outputPath;
44 }
45
46 @Override
47 public boolean isRenderDesignSpace() {
48 return renderDesignSpace;
49 }
50
51 @Override
52 public boolean isRenderStates() {
53 return renderStates;
54 }
55
56 @Override
57 public Set<FileFormat> getFormats() {
58 return formats;
59 }
60}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
new file mode 100644
index 00000000..531969b4
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerAdapterImpl.java
@@ -0,0 +1,387 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization.internal;
7
8import tools.refinery.store.map.Version;
9import tools.refinery.store.model.Interpretation;
10import tools.refinery.store.model.Model;
11import tools.refinery.store.representation.AnySymbol;
12import tools.refinery.store.representation.TruthValue;
13import tools.refinery.store.tuple.Tuple;
14import tools.refinery.visualization.ModelVisualizerAdapter;
15import tools.refinery.visualization.ModelVisualizerStoreAdapter;
16
17import java.io.*;
18import java.util.*;
19import java.util.stream.Collectors;
20
21public class ModelVisualizerAdapterImpl implements ModelVisualizerAdapter {
22 private final Model model;
23 private final ModelVisualizerStoreAdapter storeAdapter;
24 private final Map<AnySymbol, Interpretation<?>> allInterpretations;
25 private final StringBuilder designSpaceBuilder = new StringBuilder();
26 private final Map<Version, Integer> states = new HashMap<>();
27 private int transitionCounter = 0;
28 private Integer numberOfStates = 0;
29 private final String outputPath;
30 private final Set<FileFormat> formats;
31 private final boolean renderDesignSpace;
32 private final boolean renderStates;
33
34 private static final Map<Object, String> truthValueToDot = Map.of(
35 TruthValue.TRUE, "1",
36 TruthValue.FALSE, "0",
37 TruthValue.UNKNOWN, "½",
38 TruthValue.ERROR, "E",
39 true, "1",
40 false, "0"
41 );
42
43 public ModelVisualizerAdapterImpl(Model model, ModelVisualizerStoreAdapter storeAdapter) {
44 this.model = model;
45 this.storeAdapter = storeAdapter;
46 this.outputPath = storeAdapter.getOutputPath();
47 this.formats = storeAdapter.getFormats();
48 if (formats.isEmpty()) {
49 formats.add(FileFormat.SVG);
50 }
51 this.renderDesignSpace = storeAdapter.isRenderDesignSpace();
52 this.renderStates = storeAdapter.isRenderStates();
53
54 this.allInterpretations = new HashMap<>();
55 for (var symbol : storeAdapter.getStore().getSymbols()) {
56 var arity = symbol.arity();
57 if (arity < 1 || arity > 2) {
58 continue;
59 }
60 var interpretation = (Interpretation<?>) model.getInterpretation(symbol);
61 allInterpretations.put(symbol, interpretation);
62 }
63 designSpaceBuilder.append("digraph designSpace {\n");
64 designSpaceBuilder.append("""
65 nodesep=0
66 ranksep=5
67 node[
68 \tstyle=filled
69 \tfillcolor=white
70 ]
71 """);
72 }
73
74 @Override
75 public Model getModel() {
76 return model;
77 }
78
79 @Override
80 public ModelVisualizerStoreAdapter getStoreAdapter() {
81 return storeAdapter;
82 }
83
84 private String createDotForCurrentModelState() {
85
86 var unaryTupleToInterpretationsMap = new HashMap<Tuple, LinkedHashSet<Interpretation<?>>>();
87
88 var sb = new StringBuilder();
89
90 sb.append("digraph model {\n");
91 sb.append("""
92 node [
93 \tstyle="filled, rounded"
94 \tshape=plain
95 \tpencolor="#00000088"
96 \tfontname="Helvetica"
97 ]
98 """);
99 sb.append("""
100 edge [
101 \tlabeldistance=3
102 \tfontname="Helvetica"
103 ]
104 """);
105
106 for (var entry : allInterpretations.entrySet()) {
107 var key = entry.getKey();
108 var arity = key.arity();
109 var cursor = entry.getValue().getAll();
110 if (arity == 1) {
111 while (cursor.move()) {
112 unaryTupleToInterpretationsMap.computeIfAbsent(cursor.getKey(), k -> new LinkedHashSet<>())
113 .add(entry.getValue());
114 }
115 } else if (arity == 2) {
116 while (cursor.move()) {
117 var tuple = cursor.getKey();
118 for (var i = 0; i < tuple.getSize(); i++) {
119 var id = tuple.get(i);
120 unaryTupleToInterpretationsMap.computeIfAbsent(Tuple.of(id), k -> new LinkedHashSet<>());
121 }
122 sb.append(drawEdge(cursor.getKey(), key, entry.getValue()));
123 }
124 }
125 }
126 for (var entry : unaryTupleToInterpretationsMap.entrySet()) {
127 sb.append(drawElement(entry));
128 }
129 sb.append("}");
130 return sb.toString();
131 }
132
133 private StringBuilder drawElement(Map.Entry<Tuple, LinkedHashSet<Interpretation<?>>> entry) {
134 var sb = new StringBuilder();
135
136 var tableStyle = " CELLSPACING=\"0\" BORDER=\"2\" CELLBORDER=\"0\" CELLPADDING=\"4\" STYLE=\"ROUNDED\"";
137
138 var key = entry.getKey();
139 var id = key.get(0);
140 var mainLabel = String.valueOf(id);
141 var interpretations = entry.getValue();
142 var backgroundColor = toBackgroundColorString(averageColor(interpretations));
143
144 sb.append(id);
145 sb.append(" [\n");
146 sb.append("\tfillcolor=\"").append(backgroundColor).append("\"\n");
147 sb.append("\tlabel=");
148 if (interpretations.isEmpty()) {
149 sb.append("<<TABLE").append(tableStyle).append(">\n\t<TR><TD>").append(mainLabel).append("</TD></TR>");
150 }
151 else {
152 sb.append("<<TABLE").append(tableStyle).append(">\n\t\t<TR><TD COLSPAN=\"3\" BORDER=\"2\" SIDES=\"B\">")
153 .append(mainLabel).append("</TD></TR>\n");
154 for (var interpretation : interpretations) {
155 var rawValue = interpretation.get(key);
156
157 if (rawValue == null || rawValue.equals(TruthValue.FALSE) || rawValue.equals(false)) {
158 continue;
159 }
160 var color = "black";
161 if (rawValue.equals(TruthValue.ERROR)) {
162 color = "red";
163 }
164 var value = truthValueToDot.getOrDefault(rawValue, rawValue.toString());
165 var symbol = interpretation.getSymbol();
166
167 if (symbol.valueType() == String.class) {
168 value = "\"" + value + "\"";
169 }
170 sb.append("\t\t<TR><TD><FONT COLOR=\"").append(color).append("\">")
171 .append(interpretation.getSymbol().name())
172 .append("</FONT></TD><TD><FONT COLOR=\"").append(color).append("\">")
173 .append("=</FONT></TD><TD><FONT COLOR=\"").append(color).append("\">").append(value)
174 .append("</FONT></TD></TR>\n");
175 }
176 }
177 sb.append("\t\t</TABLE>>\n");
178 sb.append("]\n");
179
180 return sb;
181 }
182
183 private String drawEdge(Tuple edge, AnySymbol symbol, Interpretation<?> interpretation) {
184 var value = interpretation.get(edge);
185
186 if (value == null || value.equals(TruthValue.FALSE) || value.equals(false)) {
187 return "";
188 }
189
190 var sb = new StringBuilder();
191 var style = "solid";
192 var color = "black";
193 if (value.equals(TruthValue.UNKNOWN)) {
194 style = "dotted";
195 }
196 else if (value.equals(TruthValue.ERROR)) {
197 style = "dashed";
198 color = "red";
199 }
200
201 var from = edge.get(0);
202 var to = edge.get(1);
203 var name = symbol.name();
204 sb.append(from).append(" -> ").append(to)
205 .append(" [\n\tstyle=").append(style)
206 .append("\n\tcolor=").append(color)
207 .append("\n\tfontcolor=").append(color)
208 .append("\n\tlabel=\"").append(name)
209 .append("\"]\n");
210 return sb.toString();
211 }
212
213 private String toBackgroundColorString(Integer[] backgroundColor) {
214 if (backgroundColor.length == 3)
215 return String.format("#%02x%02x%02x", backgroundColor[0], backgroundColor[1], backgroundColor[2]);
216 else if (backgroundColor.length == 4)
217 return String.format("#%02x%02x%02x%02x", backgroundColor[0], backgroundColor[1], backgroundColor[2],
218 backgroundColor[3]);
219 return null;
220 }
221
222 private Integer[] typeColor(String name) {
223 var random = new Random(name.hashCode());
224 return new Integer[] { random.nextInt(128) + 128, random.nextInt(128) + 128, random.nextInt(128) + 128 };
225 }
226
227 private Integer[] averageColor(Set<Interpretation<?>> interpretations) {
228 if(interpretations.isEmpty()) {
229 return new Integer[]{256, 256, 256};
230 }
231 // TODO: Only use interpretations where the value is not false (or unknown)
232 var symbols = interpretations.stream()
233 .map(i -> typeColor(i.getSymbol().name())).toArray(Integer[][]::new);
234
235
236
237 return new Integer[] {
238 Arrays.stream(symbols).map(i -> i[0]).collect(Collectors.averagingInt(Integer::intValue)).intValue(),
239 Arrays.stream(symbols).map(i -> i[1]).collect(Collectors.averagingInt(Integer::intValue)).intValue(),
240 Arrays.stream(symbols).map(i -> i[2]).collect(Collectors.averagingInt(Integer::intValue)).intValue()
241 };
242 }
243
244 private String createDotForModelState(Version version) {
245 var currentVersion = model.getState();
246 model.restore(version);
247 var graph = createDotForCurrentModelState();
248 model.restore(currentVersion);
249 return graph;
250 }
251
252 private boolean saveDot(String dot, String filePath) {
253 File file = new File(filePath);
254 file.getParentFile().mkdirs();
255
256 try (FileWriter writer = new FileWriter(file)) {
257 writer.write(dot);
258 } catch (Exception e) {
259 e.printStackTrace();
260 return false;
261 }
262 return true;
263 }
264
265 private boolean renderDot(String dot, String filePath) {
266 return renderDot(dot, FileFormat.SVG, filePath);
267 }
268
269 private boolean renderDot(String dot, FileFormat format, String filePath) {
270 try {
271 Process process = new ProcessBuilder("dot", "-T" + format.getFormat(), "-o", filePath).start();
272
273 OutputStream osToProcess = process.getOutputStream();
274 PrintWriter pwToProcess = new PrintWriter(osToProcess);
275 pwToProcess.write(dot);
276 pwToProcess.close();
277 } catch (IOException e) {
278 e.printStackTrace();
279 return false;
280 }
281 return true;
282 }
283
284 @Override
285 public void addTransition(Version from, Version to, String action) {
286 designSpaceBuilder.append(states.get(from)).append(" -> ").append(states.get(to))
287 .append(" [label=\"").append(transitionCounter++).append(": ").append(action).append("\"]\n");
288 }
289
290 @Override
291 public void addTransition(Version from, Version to, String action, Tuple activation) {
292 designSpaceBuilder.append(states.get(from)).append(" -> ").append(states.get(to))
293 .append(" [label=\"").append(transitionCounter++).append(": ").append(action).append(" / ");
294
295
296 for (int i = 0; i < activation.getSize(); i++) {
297 designSpaceBuilder.append(activation.get(i));
298 if (i < activation.getSize() - 1) {
299 designSpaceBuilder.append(", ");
300 }
301 }
302 designSpaceBuilder.append("\"]\n");
303 }
304
305 @Override
306 public void addState(Version state) {
307 if (states.containsKey(state)) {
308 return;
309 }
310 states.put(state, numberOfStates++);
311 designSpaceBuilder.append(states.get(state)).append(" [URL=\"./").append(states.get(state)).append(".svg\"]\n");
312 }
313
314 @Override
315 public void addState(Version state, Collection<Double> fitness) {
316 var labelBuilder = new StringBuilder();
317 for (var f : fitness) {
318 labelBuilder.append(f).append(", ");
319 }
320 addState(state, labelBuilder.toString());
321 }
322
323 @Override
324 public void addState(Version state, String label) {
325 if (states.containsKey(state)) {
326 return;
327 }
328 states.put(state, numberOfStates++);
329 designSpaceBuilder.append(states.get(state)).append(" [label = \"").append(states.get(state)).append(" (");
330 designSpaceBuilder.append(label);
331 designSpaceBuilder.append(")\"\n").append("URL=\"./").append(states.get(state)).append(".svg\"]\n");
332 }
333
334 @Override
335 public void addSolution(Version state) {
336 addState(state);
337 designSpaceBuilder.append(states.get(state)).append(" [shape = doublecircle]\n");
338 }
339
340 private String buildDesignSpaceDot() {
341 designSpaceBuilder.append("}");
342 return designSpaceBuilder.toString();
343 }
344
345 private boolean saveDesignSpace(String path) {
346 saveDot(buildDesignSpaceDot(), path + "/designSpace.dot");
347 for (var entry : states.entrySet()) {
348 saveDot(createDotForModelState(entry.getKey()), path + "/" + entry.getValue() + ".dot");
349 }
350 return true;
351 }
352
353 private void renderDesignSpace(String path, Set<FileFormat> formats) {
354 File filePath = new File(path);
355 filePath.mkdirs();
356 if (renderStates) {
357 for (var entry : states.entrySet()) {
358 var stateId = entry.getValue();
359 var stateDot = createDotForModelState(entry.getKey());
360 for (var format : formats) {
361 if (format == FileFormat.DOT) {
362 saveDot(stateDot, path + "/" + stateId + ".dot");
363 }
364 else {
365 renderDot(stateDot, format, path + "/" + stateId + "." + format.getFormat());
366 }
367 }
368 }
369 }
370 if (renderDesignSpace) {
371 var designSpaceDot = buildDesignSpaceDot();
372 for (var format : formats) {
373 if (format == FileFormat.DOT) {
374 saveDot(designSpaceDot, path + "/designSpace.dot");
375 }
376 else {
377 renderDot(designSpaceDot, format, path + "/designSpace." + format.getFormat());
378 }
379 }
380 }
381 }
382
383 @Override
384 public void visualize() {
385 renderDesignSpace(outputPath, formats);
386 }
387}
diff --git a/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
new file mode 100644
index 00000000..e4d801d8
--- /dev/null
+++ b/subprojects/store-dse-visualization/src/main/java/tools/refinery/visualization/internal/ModelVisualizerBuilderImpl.java
@@ -0,0 +1,55 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: EPL-2.0
5 */
6package tools.refinery.visualization.internal;
7
8import tools.refinery.store.adapter.AbstractModelAdapterBuilder;
9import tools.refinery.store.model.ModelStore;
10import tools.refinery.visualization.ModelVisualizerBuilder;
11
12import java.util.LinkedHashSet;
13import java.util.Set;
14
15public class ModelVisualizerBuilderImpl
16 extends AbstractModelAdapterBuilder<ModelVisualizeStoreAdapterImpl>
17 implements ModelVisualizerBuilder {
18 private String outputPath;
19 private boolean saveDesignSpace = false;
20 private boolean saveStates = false;
21 private Set<FileFormat> formats = new LinkedHashSet<>();
22
23 @Override
24 protected ModelVisualizeStoreAdapterImpl doBuild(ModelStore store) {
25 return new ModelVisualizeStoreAdapterImpl(store, outputPath, formats, saveDesignSpace, saveStates);
26 }
27
28 @Override
29 public ModelVisualizerBuilder withOutputpath(String outputpath) {
30 checkNotConfigured();
31 this.outputPath = outputpath;
32 return this;
33 }
34
35 @Override
36 public ModelVisualizerBuilder withFormat(FileFormat format) {
37 checkNotConfigured();
38 this.formats.add(format);
39 return this;
40 }
41
42 @Override
43 public ModelVisualizerBuilder saveDesignSpace() {
44 checkNotConfigured();
45 this.saveDesignSpace = true;
46 return this;
47 }
48
49 @Override
50 public ModelVisualizerBuilder saveStates() {
51 checkNotConfigured();
52 this.saveStates = true;
53 return this;
54 }
55}