View Javadoc

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     ///                              NODES
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         // default is good for artifact
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             //properties.put("style","filled");
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         // Note, I should compute effective account membership
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     // returns the first non transparent color
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         // Note, I should compute effective account membership
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         // Note, I should compute effective account membership
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     ///                              EDGES
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     /* Displays type if any, role otherwise. */
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     ///                              DOT FORMAT GENERATION
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