MATSIM
GraphvizRenderer.java
Go to the documentation of this file.
1 package org.matsim.guice;
2 
3 import com.google.common.base.Joiner;
4 import com.google.common.collect.ImmutableList;
5 import com.google.common.collect.Lists;
6 import com.google.common.collect.Maps;
7 import com.google.inject.Key;
8 import com.google.inject.grapher.BindingEdge;
9 import com.google.inject.grapher.DependencyEdge;
10 import com.google.inject.grapher.Edge;
11 import com.google.inject.grapher.ImplementationNode;
12 import com.google.inject.grapher.InstanceNode;
13 import com.google.inject.grapher.InterfaceNode;
14 import com.google.inject.grapher.NameFactory;
15 import com.google.inject.grapher.Node;
16 import com.google.inject.grapher.NodeId;
17 import com.google.inject.grapher.ShortNameFactory;
18 import com.google.inject.grapher.graphviz.ArrowType;
19 import com.google.inject.grapher.graphviz.CompassPoint;
20 import com.google.inject.grapher.graphviz.EdgeStyle;
21 import com.google.inject.grapher.graphviz.GraphvizEdge;
22 import com.google.inject.grapher.graphviz.GraphvizNode;
23 import com.google.inject.grapher.graphviz.NodeStyle;
24 import com.google.inject.grapher.graphviz.PortIdFactory;
25 import com.google.inject.grapher.graphviz.PortIdFactoryImpl;
26 import com.google.inject.spi.InjectionPoint;
27 import org.jgrapht.Graph;
28 
29 import java.io.PrintWriter;
30 import java.lang.reflect.Member;
31 import java.util.List;
32 import java.util.Map;
33 
34 public class GraphvizRenderer {
35 
36  private boolean fields = false;
37 
38  private final Map<NodeId, GraphvizNode> nodes = Maps.newHashMap();
39  private final List<GraphvizEdge> edges = Lists.newArrayList();
40  private final NameFactory nameFactory = new ShortNameFactory();
41  private final PortIdFactory portIdFactory = new PortIdFactoryImpl();
42 
43  private PrintWriter out;
44  private String rankdir = "TB";
45 
46  public void render(Graph<Node, Edge> graph) {
47  for (Node node : graph.vertexSet()) {
48  if (node instanceof InstanceNode) {
49  newInstanceNode(((InstanceNode) node));
50  } else if (node instanceof ImplementationNode) {
51  newImplementationNode(((ImplementationNode) node));
52  } else if (node instanceof InterfaceNode) {
53  newInterfaceNode(((InterfaceNode) node));
54  }
55  }
56  for (Edge edge : graph.edgeSet()) {
57  if (edge instanceof BindingEdge) {
58  newBindingEdge(((BindingEdge) edge));
59  } else if (edge instanceof DependencyEdge) {
60  newDependencyEdge(((DependencyEdge) edge));
61  }
62  }
63  out.println("digraph injector {");
64 
65  Map<String, String> attrs = Maps.newHashMap();
66  attrs.put("rankdir", rankdir);
67  out.println("graph " + getAttrString(attrs) + ";");
68 
69  for (GraphvizNode node : nodes.values()) {
70  renderNode(node);
71  }
72 
73  for (GraphvizEdge edge : edges) {
74  renderEdge(edge);
75  }
76 
77 // out.println("{");
78 // out.println("rank=same;");
79 // out.println(nodes.get(NodeId.newTypeId(Key.get(Mobsim.class))).getIdentifier()+";");
80 // out.println(nodes.get(NodeId.newTypeId(Key.get(TripRouter.class))).getIdentifier()+";");
81 // out.println(nodes.get(NodeId.newTypeId(Key.get(PlansScoring.class))).getIdentifier()+";");
82 // out.println(nodes.get(NodeId.newTypeId(Key.get(PrepareForSim.class))).getIdentifier()+";");
83 // out.println(nodes.get(NodeId.newTypeId(Key.get(PlansReplanning.class))).getIdentifier()+";");
84 // out.println("}");
85 //
86 // out.println("{");
87 // out.println("rank=same;");
88 // out.println(nodes.get(NodeId.newTypeId(Key.get(RoutingModule.class, Names.named("car")))).getIdentifier()+";");
89 // out.println(nodes.get(NodeId.newTypeId(Key.get(TravelTime.class, Names.named("car")))).getIdentifier()+";");
90 // out.println(nodes.get(NodeId.newTypeId(Key.get(TravelDisutilityFactory.class, Names.named("car")))).getIdentifier()+";");
91 // out.println("}");
92 
93  finish();
94 
95  out.flush();
96  }
97 
98 
99  protected void reset() {
100  nodes.clear();
101  edges.clear();
102  }
103 
104  public void setOut(PrintWriter out) {
105  this.out = out;
106  }
107 
108  void setRankdir(String rankdir) {
109  this.rankdir = rankdir;
110  }
111 
112  protected void finish() {
113  out.println("}");
114  }
115 
116  private void renderNode(GraphvizNode node) {
117  Map<String, String> attrs = getNodeAttributes(node);
118  out.println(node.getIdentifier() + " " + getAttrString(attrs));
119  }
120 
121  private Map<String, String> getNodeAttributes(GraphvizNode node) {
122  Map<String, String> attrs = Maps.newHashMap();
123 
124  attrs.put("label", getNodeLabel(node));
125  // remove most of the margin because the table has internal padding
126  attrs.put("margin", "\"0.02,0\"");
127  attrs.put("shape", node.getShape().toString());
128  attrs.put("style", node.getStyle().toString());
129 
130  return attrs;
131  }
132 
138  private String getNodeLabel(GraphvizNode node) {
139  String cellborder = node.getStyle() == NodeStyle.INVISIBLE ? "1" : "0";
140 
141  StringBuilder html = new StringBuilder();
142  html.append("<");
143  html.append("<table cellspacing=\"0\" cellpadding=\"5\" cellborder=\"");
144  html.append(cellborder).append("\" border=\"0\">");
145 
146  html.append("<tr>").append("<td align=\"left\" port=\"header\" ");
147  html.append("bgcolor=\"" + node.getHeaderBackgroundColor() + "\">");
148 
149  String subtitle = Joiner.on("<br align=\"left\"/>").join(node.getSubtitles());
150  if (subtitle.length() != 0) {
151  html.append("<font color=\"").append(node.getHeaderTextColor());
152  html.append("\" point-size=\"10\">");
153  html.append(subtitle).append("<br align=\"left\"/>").append("</font>");
154  }
155 
156  html.append("<font color=\"" + node.getHeaderTextColor() + "\">");
157  html.append(htmlEscape(node.getTitle())).append("<br align=\"left\"/>");
158  html.append("</font>").append("</td>").append("</tr>");
159 
160  for (Map.Entry<String, String> field : node.getFields().entrySet()) {
161  html.append("<tr>");
162  html.append("<td align=\"left\" port=\"").append(htmlEscape(field.getKey())).append("\">");
163  html.append(htmlEscape(field.getValue()));
164  html.append("</td>").append("</tr>");
165  }
166 
167  html.append("</table>");
168  html.append(">");
169  return html.toString();
170  }
171 
172  private void renderEdge(GraphvizEdge edge) {
173  Map<String, String> attrs = getEdgeAttributes(edge);
174 
175  String tailId = getEdgeEndPoint(nodes.get(edge.getTailNodeId()).getIdentifier(),
176  edge.getTailPortId(), edge.getTailCompassPoint());
177 
178  String headId = getEdgeEndPoint(nodes.get(edge.getHeadNodeId()).getIdentifier(),
179  edge.getHeadPortId(), edge.getHeadCompassPoint());
180 
181  out.println(tailId + " -> " + headId + " " + getAttrString(attrs));
182  }
183 
184  private Map<String, String> getEdgeAttributes(GraphvizEdge edge) {
185  Map<String, String> attrs = Maps.newHashMap();
186 
187  attrs.put("arrowhead", getArrowString(edge.getArrowHead()));
188  attrs.put("arrowtail", getArrowString(edge.getArrowTail()));
189  attrs.put("style", edge.getStyle().toString());
190 
191  return attrs;
192  }
193 
194  private String getAttrString(Map<String, String> attrs) {
195  List<String> attrList = Lists.newArrayList();
196 
197  for (Map.Entry<String, String> attr : attrs.entrySet()) {
198  String value = attr.getValue();
199 
200  if (value != null) {
201  attrList.add(attr.getKey() + "=" + value);
202  }
203  }
204 
205  return "[" + Joiner.on(", ").join(attrList) + "]";
206  }
207 
213  private String getArrowString(List<ArrowType> arrows) {
214  return Joiner.on("").join(arrows);
215  }
216 
217  private String getEdgeEndPoint(String nodeId, String portId, CompassPoint compassPoint) {
218  List<String> portStrings = Lists.newArrayList(nodeId);
219 
220  if (portId != null) {
221  portStrings.add(portId);
222  }
223 
224  if (compassPoint != null) {
225  portStrings.add(compassPoint.toString());
226  }
227 
228  return Joiner.on(":").join(portStrings);
229  }
230 
231  private String htmlEscape(String str) {
232  return str.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
233  }
234 
235  private void newInterfaceNode(InterfaceNode node) {
236  NodeId nodeId = node.getId();
237  GraphvizNode gnode = new GraphvizNode(nodeId);
238  gnode.setStyle(NodeStyle.DASHED);
239  Key<?> key = nodeId.getKey();
240  gnode.setTitle(nameFactory.getClassName(key));
241  gnode.addSubtitle(0, nameFactory.getAnnotationName(key));
242  addNode(gnode);
243  }
244 
245  private void newImplementationNode(ImplementationNode node) {
246  NodeId nodeId = node.getId();
247  GraphvizNode gnode = new GraphvizNode(nodeId);
248  gnode.setStyle(NodeStyle.SOLID);
249 
250  gnode.setHeaderBackgroundColor("#000000");
251  gnode.setHeaderTextColor("#ffffff");
252  gnode.setTitle(nameFactory.getClassName(nodeId.getKey()));
253 
254  if (fields) {
255  for (Member member : node.getMembers()) {
256  gnode.addField(portIdFactory.getPortId(member), nameFactory.getMemberName(member));
257  }
258  }
259 
260  addNode(gnode);
261  }
262 
263  private void newInstanceNode(InstanceNode node) {
264  NodeId nodeId = node.getId();
265  GraphvizNode gnode = new GraphvizNode(nodeId);
266  gnode.setStyle(NodeStyle.SOLID);
267 
268  gnode.setHeaderBackgroundColor("#000000");
269  gnode.setHeaderTextColor("#ffffff");
270  gnode.setTitle(nameFactory.getClassName(nodeId.getKey()));
271 
272  gnode.addSubtitle(0, nameFactory.getSourceName(node.getSource()));
273 
274  gnode.setHeaderBackgroundColor("#aaaaaa");
275  gnode.setHeaderTextColor("#ffffff");
276  gnode.setTitle(nameFactory.getInstanceName(node.getInstance()));
277 
278  if (fields) {
279  for (Member member : node.getMembers()) {
280  gnode.addField(portIdFactory.getPortId(member), nameFactory.getMemberName(member));
281  }
282  }
283  addNode(gnode);
284  }
285 
286  private void newDependencyEdge(DependencyEdge edge) {
287  GraphvizEdge gedge = new GraphvizEdge(edge.getFromId(), edge.getToId());
288  InjectionPoint fromPoint = edge.getInjectionPoint();
289  if (fromPoint == null) {
290  gedge.setTailPortId("header");
291  } else {
292  gedge.setTailPortId(portIdFactory.getPortId(fromPoint.getMember()));
293  }
294  gedge.setArrowHead(ImmutableList.of(ArrowType.NORMAL));
295  gedge.setTailCompassPoint(CompassPoint.EAST);
296 
297  edges.add(gedge);
298  }
299 
300  private void newBindingEdge(BindingEdge edge) {
301  GraphvizEdge gedge = new GraphvizEdge(edge.getFromId(), edge.getToId());
302  gedge.setStyle(EdgeStyle.DASHED);
303  switch (edge.getType()) {
304  case NORMAL:
305  gedge.setArrowHead(ImmutableList.of(ArrowType.NORMAL_OPEN));
306  break;
307 
308  case PROVIDER:
309  gedge.setArrowHead(ImmutableList.of(ArrowType.NORMAL_OPEN, ArrowType.NORMAL_OPEN));
310  break;
311 
312  case CONVERTED_CONSTANT:
313  gedge.setArrowHead(ImmutableList.of(ArrowType.NORMAL_OPEN, ArrowType.DOT_OPEN));
314  break;
315  }
316  edges.add(gedge);
317  }
318 
319  private void addNode(GraphvizNode node) {
320  node.setIdentifier("x" + nodes.size());
321  nodes.put(node.getNodeId(), node);
322  }
323 
324 }
final Map< NodeId, GraphvizNode > nodes
String getAttrString(Map< String, String > attrs)
Map< String, String > getNodeAttributes(GraphvizNode node)
Map< String, String > getEdgeAttributes(GraphvizEdge edge)
String getEdgeEndPoint(String nodeId, String portId, CompassPoint compassPoint)
void render(Graph< Node, Edge > graph)
void newBindingEdge(BindingEdge edge)
void newDependencyEdge(DependencyEdge edge)
void renderEdge(GraphvizEdge edge)
final List< GraphvizEdge > edges
void newImplementationNode(ImplementationNode node)
void renderNode(GraphvizNode node)
String getArrowString(List< ArrowType > arrows)
String getNodeLabel(GraphvizNode node)
void newInstanceNode(InstanceNode node)
void newInterfaceNode(InterfaceNode node)