1 package org.openprovenance.model;
2 import java.util.List;
3 import java.util.HashMap;
4 import java.util.LinkedList;
5 import java.io.File;
6 import java.io.InputStream;
7 import java.io.PrintStream;
8 import java.io.FileOutputStream;
9 import java.io.OutputStream;
10 import javax.xml.bind.JAXBContext;
11 import javax.xml.bind.Unmarshaller;
12 import javax.xml.bind.JAXBException;
13 import javax.xml.bind.JAXBElement;
14 import org.w3c.dom.Element;
15
16 import org.openprovenance.model.printer.OPMPrinterConfiguration;
17 import org.openprovenance.model.printer.AgentMapEntry;
18 import org.openprovenance.model.printer.AccountColorMapEntry;
19 import org.openprovenance.model.printer.ArtifactMapEntry;
20 import org.openprovenance.model.printer.ProcessMapEntry;
21 import org.openprovenance.model.printer.EdgeStyleMapEntry;
22 import org.openprovenance.model.printer.OPMPrinterConfigDeserialiser;
23
24 /*** Serialisation of OPM Graphs to DOT format. */
25 public class OPMToDot {
26 public final static String DEFAULT_CONFIGURATION_FILE="defaultConfig.xml";
27 public final static String DEFAULT_CONFIGURATION_FILE_WITH_ROLE="defaultConfigWithRole.xml";
28 public final static String USAGE="opm2dot opmFile.xml out.dot out.pdf [configuration.xml]";
29
30 OPMUtilities u=new OPMUtilities();
31 OPMFactory of=new OPMFactory();
32
33
34
35 public static void main(String [] args) throws Exception {
36 if ((args==null) || (args.length==0) || (args.length>4)) {
37 System.out.println(USAGE);
38 return;
39 }
40
41 String opmFile=args[0];
42 String outDot=args[1];
43 String outPdf=args[2];
44 String configFile=((args.length==4) ? args[3] : null);
45
46 OPMToDot converter=((configFile==null) ? new OPMToDot() : new OPMToDot(configFile));
47
48 converter.convert(opmFile,outDot,outPdf);
49 }
50
51
52 public OPMToDot() {
53 InputStream is=this.getClass().getClassLoader().getResourceAsStream(DEFAULT_CONFIGURATION_FILE);
54 init(is);
55 }
56 public OPMToDot(boolean withRoleFlag) {
57 InputStream is;
58 if (withRoleFlag) {
59 is=this.getClass().getClassLoader().getResourceAsStream(DEFAULT_CONFIGURATION_FILE_WITH_ROLE);
60 } else {
61 is=this.getClass().getClassLoader().getResourceAsStream(DEFAULT_CONFIGURATION_FILE);
62 }
63 init(is);
64 }
65
66 public OPMToDot(String configurationFile) {
67 this();
68 init(configurationFile);
69 }
70
71 public OPMPrinterConfigDeserialiser getDeserialiser() {
72 return OPMPrinterConfigDeserialiser.getThreadOPMPrinterConfigDeserialiser();
73 }
74
75 public void init(String configurationFile) {
76 OPMPrinterConfigDeserialiser printerDeserial=getDeserialiser();
77 try {
78 OPMPrinterConfiguration opc=printerDeserial.deserialiseOPMPrinterConfiguration(new File(configurationFile));
79 init(opc);
80 } catch (JAXBException je) {
81 je.printStackTrace();
82 }
83 }
84
85 public void init(InputStream is) {
86 OPMPrinterConfigDeserialiser printerDeserial=getDeserialiser();
87 try {
88 OPMPrinterConfiguration opc=printerDeserial.deserialiseOPMPrinterConfiguration(is);
89 init(opc);
90 } catch (JAXBException je) {
91 je.printStackTrace();
92 }
93 }
94
95 public void init(OPMPrinterConfiguration configuration) {
96 if (configuration==null) return;
97
98 if (configuration.getEdges()!=null) {
99 if (configuration.getEdges().getDefault()!=null) {
100 defaultEdgeStyle=configuration.getEdges().getDefault();
101 }
102
103 for (EdgeStyleMapEntry edge: configuration.getEdges().getEdge()) {
104 edgeStyleMap.put(edge.getType(),edge);
105 }
106 }
107
108 if (configuration.getProcesses()!=null) {
109 if (configuration.getProcesses().isDisplayValue()!=null) {
110 this.displayProcessValue=configuration.getProcesses().isDisplayValue();
111 }
112 if (configuration.getProcesses().isColoredAsAccount()!=null) {
113 this.displayProcessColor=configuration.getProcesses().isColoredAsAccount();
114 }
115 for (ProcessMapEntry process: configuration.getProcesses().getProcess()) {
116 processNameMap.put(process.getValue(),process.getDisplay());
117 }
118 }
119
120 if (configuration.getArtifacts()!=null) {
121 if (configuration.getArtifacts().isDisplayValue()!=null) {
122 this.displayArtifactValue=configuration.getArtifacts().isDisplayValue();
123 }
124 if (configuration.getArtifacts().isColoredAsAccount()!=null) {
125 this.displayArtifactColor=configuration.getArtifacts().isColoredAsAccount();
126 }
127 for (ArtifactMapEntry artifact: configuration.getArtifacts().getArtifact()) {
128 artifactNameMap.put(artifact.getValue(),artifact.getDisplay());
129 }
130 }
131
132 if (configuration.getAgents()!=null) {
133 if (configuration.getAgents().isDisplayValue()!=null) {
134 this.displayAgentValue=configuration.getAgents().isDisplayValue();
135 }
136 if (configuration.getAgents().isColoredAsAccount()!=null) {
137 this.displayAgentColor=configuration.getAgents().isColoredAsAccount();
138 }
139 for (AgentMapEntry agent: configuration.getAgents().getAgent()) {
140 agentNameMap.put(agent.getValue(),agent.getDisplay());
141 }
142 }
143
144 if (configuration.getAccounts()!=null) {
145 if (configuration.getAccounts().getDefaultAccount()!=null) {
146 this.defaultAccountLabel=configuration.getAccounts().getDefaultAccount();
147 }
148 if (configuration.getAccounts().getDefaultColor()!=null) {
149 this.defaultAccountColor=configuration.getAccounts().getDefaultColor();
150 }
151 for (AccountColorMapEntry account: configuration.getAccounts().getAccount()) {
152 accountColourMap.put(account.getName(),account.getColor());
153 }
154 }
155
156 if (configuration.getGraphName()!=null) {
157 this.name=configuration.getGraphName();
158 }
159
160 }
161
162 public void convert(String opmFile, String dotFile, String pdfFile)
163 throws java.io.FileNotFoundException, java.io.IOException, JAXBException {
164 convert (OPMDeserialiser.getThreadOPMDeserialiser().deserialiseOPMGraph(new File(opmFile)),dotFile,pdfFile);
165 }
166
167 public void convert(OPMGraph graph, String dotFile, String pdfFile)
168 throws java.io.FileNotFoundException, java.io.IOException {
169 convert(graph,new File(dotFile));
170 Runtime runtime = Runtime.getRuntime();
171 java.lang.Process proc = runtime.exec("dot -o " + pdfFile + " -Tpdf " + dotFile);
172 }
173
174 public void convert(OPMGraph graph, File file) throws java.io.FileNotFoundException{
175 OutputStream os=new FileOutputStream(file);
176 convert(graph, new PrintStream(os));
177 }
178
179 public void convert(OPMGraph graph, PrintStream out) {
180 List<Edge> edges=u.getEdges(graph);
181
182 prelude(out);
183
184 if (graph.getProcesses()!=null) {
185 for (Process p: graph.getProcesses().getProcess()) {
186 emitProcess(p,out);
187 }
188 }
189
190 if (graph.getArtifacts()!=null) {
191 for (Artifact p: graph.getArtifacts().getArtifact()) {
192 emitArtifact(p,out);
193 }
194 }
195
196 if (graph.getAgents()!=null) {
197 for (Agent p: graph.getAgents().getAgent()) {
198 emitAgent(p,out);
199 }
200 }
201
202 for (Edge e: edges) {
203 emitDependency(e,out);
204 }
205
206
207 postlude(out);
208
209 }
210
211
212
213
214
215
216
217 public void emitProcess(Process p, PrintStream out) {
218 HashMap<String,String> properties=new HashMap();
219
220 emitNode(p.getId(),
221 addProcessShape(p,addProcessLabel(p, addProcessColor(p,properties))),
222 out);
223
224 for (JAXBElement<? extends EmbeddedAnnotation> ann: p.getAnnotation()) {
225 EmbeddedAnnotation emb=ann.getValue();
226 of.expandAnnotation(emb);
227 if (filterAnnotation(emb)) emitAnnotation(p.getId(), emb,out);
228 }
229
230 }
231
232 public void emitArtifact(Artifact a, PrintStream out) {
233 HashMap<String,String> properties=new HashMap();
234
235 emitNode(a.getId(),
236 addArtifactShape(a,addArtifactLabel(a, addArtifactColor(a,properties))),
237 out);
238 for (JAXBElement<? extends EmbeddedAnnotation> ann: a.getAnnotation()) {
239 EmbeddedAnnotation emb=ann.getValue();
240 of.expandAnnotation(emb);
241 if (filterAnnotation(emb)) emitAnnotation(a.getId(), emb,out);
242 }
243 }
244
245 public void emitAgent(Agent ag, PrintStream out) {
246 HashMap<String,String> properties=new HashMap();
247
248 emitNode(ag.getId(),
249 addAgentShape(ag,addAgentLabel(ag, addAgentColor(ag,properties))),
250 out);
251
252 for (JAXBElement<? extends EmbeddedAnnotation> ann: ag.getAnnotation()) {
253 EmbeddedAnnotation emb=ann.getValue();
254 of.expandAnnotation(emb);
255 if (filterAnnotation(emb)) emitAnnotation(ag.getId(), emb,out);
256 }
257
258 }
259
260 public void emitAnnotation(String id, EmbeddedAnnotation ann, PrintStream out) {
261 HashMap<String,String> properties=new HashMap();
262 String newId=annotationId(ann.getId(),id);
263 emitNode(newId,
264 addAnnotationShape(ann,addAnnotationColor(ann,addAnnotationLabel(ann,properties))),
265 out);
266 HashMap<String,String> linkProperties=new HashMap();
267 emitEdge(newId,id,addAnnotationLinkProperties(ann,linkProperties),out,true);
268 }
269
270 public boolean filterAnnotation(EmbeddedAnnotation ann) {
271 if (ann instanceof Label) {
272 return false;
273 } else {
274 return true;
275 }
276 }
277
278 int annotationCount=0;
279 public String annotationId(String id,String node) {
280 if (id==null) {
281 return "ann" + node + (annotationCount++);
282 } else {
283 return id;
284 }
285 }
286
287 public HashMap<String,String> addAnnotationLinkProperties(EmbeddedAnnotation ann, HashMap<String,String> properties) {
288 properties.put("arrowhead","none");
289 properties.put("style","dashed");
290 properties.put("color","gray");
291 return properties;
292 }
293
294 public HashMap<String,String> addProcessShape(Process p, HashMap<String,String> properties) {
295 properties.put("shape","polygon");
296 properties.put("sides","4");
297 return properties;
298 }
299
300 public HashMap<String,String> addProcessLabel(Process p, HashMap<String,String> properties) {
301 properties.put("label",processLabel(p));
302 return properties;
303 }
304
305 public HashMap<String,String> addProcessColor(Process p, HashMap<String,String> properties) {
306 if (displayProcessColor) {
307 properties.put("color",processColor(p));
308 properties.put("fontcolor",processColor(p));
309 }
310 return properties;
311 }
312
313 public HashMap<String,String> addArtifactShape(Artifact p, HashMap<String,String> properties) {
314
315 return properties;
316 }
317
318 public HashMap<String,String> addArtifactColor(Artifact a, HashMap<String,String> properties) {
319 if (displayArtifactColor) {
320 properties.put("color",artifactColor(a));
321 properties.put("fontcolor",artifactColor(a));
322 }
323 return properties;
324 }
325
326 public HashMap<String,String> addArtifactLabel(Artifact p, HashMap<String,String> properties) {
327 properties.put("label",artifactLabel(p));
328 return properties;
329 }
330
331 public HashMap<String,String> addAgentShape(Agent p, HashMap<String,String> properties) {
332 properties.put("shape","polygon");
333 properties.put("sides","8");
334 return properties;
335 }
336
337 public HashMap<String,String> addAgentLabel(Agent p, HashMap<String,String> properties) {
338 properties.put("label",agentLabel(p));
339 return properties;
340 }
341
342 public HashMap<String,String> addAgentColor(Agent a, HashMap<String,String> properties) {
343 if (displayAgentColor) {
344 properties.put("color",agentColor(a));
345 properties.put("fontcolor",agentColor(a));
346 }
347 return properties;
348 }
349
350 public HashMap<String,String> addAnnotationShape(EmbeddedAnnotation ann, HashMap<String,String> properties) {
351 properties.put("shape","note");
352 return properties;
353 }
354 public HashMap<String,String> addAnnotationLabel(EmbeddedAnnotation ann, HashMap<String,String> properties) {
355 String label="";
356 label=label+"<<TABLE cellpadding=\"0\" border=\"0\">\n";
357 for (Property prop: ann.getProperty()) {
358 label=label+" <TR>\n";
359 label=label+" <TD align=\"left\">" + convertProperty(prop.getUri()) + ":</TD>\n";
360 label=label+" <TD align=\"left\">" + prop.getValue() + "</TD>\n";
361 label=label+" </TR>\n";
362 }
363 label=label+" </TABLE>>\n";
364 properties.put("label",label);
365 return properties;
366 }
367
368 public String convertProperty(String label) {
369 int i=label.lastIndexOf("#");
370 int j=label.lastIndexOf("/");
371 return label.substring(Math.max(i,j)+1, label.length());
372 }
373
374
375 public HashMap<String,String> addAnnotationColor(EmbeddedAnnotation ann, HashMap<String,String> properties) {
376 if (displayAnnotationColor) {
377 properties.put("color",annotationColor(ann));
378 properties.put("fontcolor","black");
379
380 }
381 return properties;
382 }
383
384
385 boolean displayProcessValue=false;
386 boolean displayProcessColor=false;
387 boolean displayArtifactValue=false;
388 boolean displayArtifactColor=false;
389 boolean displayAgentColor=false;
390 boolean displayAgentValue=false;
391 boolean displayAnnotationColor=true;
392
393 public String processLabel(Process p) {
394 if (displayProcessValue) {
395 return convertProcessName(""+of.getLabel(p));
396 } else {
397 return p.getId();
398 }
399 }
400 public String processColor(Process p) {
401
402 List<String> colors=new LinkedList();
403 for (AccountRef acc: p.getAccount()) {
404 String accountLabel=((Account)acc.getRef()).getId();
405 String colour=convertAccount(accountLabel);
406 colors.add(colour);
407 }
408
409 return selectColor(colors);
410 }
411
412
413 public String selectColor(List<String> colors) {
414 String tr="transparent";
415 for (String c: colors) {
416 if (!(c.equals(tr))) return c;
417 }
418 return tr;
419 }
420
421 public String artifactLabel(Artifact p) {
422 if (displayArtifactValue) {
423 return convertArtifactName(""+of.getLabel(p));
424 } else {
425 return p.getId();
426 }
427 }
428 public String artifactColor(Artifact p) {
429
430 List<String> colors=new LinkedList();
431 for (AccountRef acc: p.getAccount()) {
432 String accountLabel=((Account)acc.getRef()).getId();
433 String colour=convertAccount(accountLabel);
434 colors.add(colour);
435 }
436 return selectColor(colors);
437 }
438 public String agentColor(Agent p) {
439
440 List<String> colors=new LinkedList();
441 for (AccountRef acc: p.getAccount()) {
442 String accountLabel=((Account)acc.getRef()).getId();
443 String colour=convertAccount(accountLabel);
444 colors.add(colour);
445 }
446 return selectColor(colors);
447 }
448
449
450 public String annotationColor(EmbeddedAnnotation ann) {
451 List<String> colors=new LinkedList();
452 colors.add("gray");
453 return selectColor(colors);
454 }
455
456 public String agentLabel(Agent p) {
457 if (displayAgentValue) {
458 return convertAgentName(""+of.getLabel(p));
459 } else {
460 return p.getId();
461 }
462 }
463
464 HashMap<String,String> processNameMap=new HashMap<String,String>();
465 public String convertProcessName(String process) {
466 String name=processNameMap.get(process);
467 if (name!=null) return name;
468 return process;
469 }
470 HashMap<String,String> artifactNameMap=new HashMap<String,String>();
471 public String convertArtifactName(String artifact) {
472 String name=artifactNameMap.get(artifact);
473 if (name!=null) return name;
474 return artifact;
475 }
476 HashMap<String,String> agentNameMap=new HashMap<String,String>();
477 public String convertAgentName(String agent) {
478 String name=agentNameMap.get(agent);
479 if (name!=null) return name;
480 return agent;
481 }
482
483
484
485
486
487
488
489
490 public void emitDependency(Edge e, PrintStream out) {
491 HashMap<String,String> properties=new HashMap();
492
493 List<AccountRef> accounts=e.getAccount();
494 if (accounts.isEmpty()) {
495 accounts=new LinkedList();
496 accounts.add(of.newAccountRef(of.newAccount(defaultAccountLabel)));
497 }
498
499 for (AccountRef acc: accounts) {
500 String accountLabel=((Account)acc.getRef()).getId();
501 addEdgeAttributes(accountLabel,e,properties);
502 emitEdge( ((Node)e.getEffect().getRef()).getId(),
503 ((Node)e.getCause().getRef()).getId(),
504 properties,
505 out,
506 true);
507 }
508 }
509
510 public HashMap<String,String> addEdgeAttributes(String accountLabel,
511 Edge e,
512 HashMap<String,String> properties) {
513 String colour=convertAccount(accountLabel);
514 properties.put("color",colour);
515 properties.put("fontcolor",colour);
516 properties.put("style",getEdgeStyle(e));
517 addEdgeLabel(e,properties);
518 return properties;
519 }
520
521
522
523 public void addEdgeLabel(Edge e, HashMap<String,String> properties) {
524 String label=null;
525 String type=of.getType(e);
526 if (type!=null) {
527 label=type;
528 } else if (getEdgePrintRole(e)) {
529 Role role=of.getRole(e);
530 if (role!=null && role.getValue()!=null) {
531 label=displayRole(role.getValue());
532 properties.put("fontsize","8");
533 }
534 }
535 if (label!=null) {
536 properties.put("label",convertEdgeLabel(label));
537 if (properties.get("fontsize")==null) {
538 properties.put("fontsize","10");
539 }
540 }
541 }
542
543 public String displayRole(String role) {
544 return "(" + role + ")";
545 }
546
547 public String convertEdgeLabel(String label) {
548 return label.substring(label.indexOf("#")+1, label.length());
549 }
550
551
552 HashMap<String,String> accountColourMap=new HashMap<String,String>();
553 public String convertAccount(String account) {
554 String colour=accountColourMap.get(account);
555 if (colour!=null) return colour;
556 return defaultAccountColor;
557 }
558
559 String defaultEdgeStyle;
560 HashMap<String,EdgeStyleMapEntry> edgeStyleMap=new HashMap<String,EdgeStyleMapEntry>();
561
562 public String getEdgeStyle(Edge edge) {
563 String name=edge.getClass().getName();
564 EdgeStyleMapEntry style=edgeStyleMap.get(name);
565 if (style!=null) return style.getStyle();
566 return defaultEdgeStyle;
567 }
568
569 public boolean getEdgePrintRole(Edge edge) {
570 String name=edge.getClass().getName();
571 EdgeStyleMapEntry style=edgeStyleMap.get(name);
572 if (style!=null) {
573 Boolean flag=style.isPrintRole();
574 if (flag==null) return false;
575 return flag;
576 } else {
577 return false;
578 }
579 }
580
581
582
583
584
585
586
587
588
589 String name;
590 String defaultAccountLabel;
591 String defaultAccountColor;
592
593
594 public void emitNode(String name, HashMap<String,String> properties, PrintStream out) {
595 StringBuffer sb=new StringBuffer();
596 sb.append(name);
597 emitProperties(sb,properties);
598 out.println(sb.toString());
599 }
600
601
602 public void emitEdge(String src, String dest, HashMap<String,String> properties, PrintStream out, boolean directional) {
603 StringBuffer sb=new StringBuffer();
604 sb.append(src);
605 if (directional) {
606 sb.append(" -> ");
607 } else {
608 sb.append(" -- ");
609 }
610 sb.append(dest);
611 emitProperties(sb,properties);
612 out.println(sb.toString());
613 }
614
615 public void emitProperties(StringBuffer sb,HashMap<String,String> properties) {
616 sb.append(" [");
617 boolean first=true;
618 for (String key: properties.keySet()) {
619 if (first) {
620 first=false;
621 } else {
622 sb.append(",");
623 }
624 String value=properties.get(key);
625 sb.append(key);
626 if (value.startsWith("<")) {
627 sb.append("=");
628 sb.append(value);
629 } else {
630 sb.append("=\"");
631 sb.append(value);
632 sb.append("\"");
633 }
634
635
636 }
637 sb.append("]");
638 }
639
640 void prelude(PrintStream out) {
641 out.println("digraph " + name + " { rankdir=\"BT\"; ");
642 }
643
644 void postlude(PrintStream out) {
645 out.println("}");
646 out.close();
647 }
648
649
650
651
652
653
654 }
655
656