001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.tang.util.walk.graphviz; 020 021import org.apache.reef.tang.implementation.Constructor; 022import org.apache.reef.tang.implementation.InjectionPlan; 023import org.apache.reef.tang.implementation.Subplan; 024import org.apache.reef.tang.implementation.java.JavaInstance; 025import org.apache.reef.tang.util.walk.AbstractInjectionPlanNodeVisitor; 026import org.apache.reef.tang.util.walk.EdgeVisitor; 027import org.apache.reef.tang.util.walk.Walk; 028 029/** 030 * Build a Graphviz representation of the injection plan graph. 031 */ 032public final class GraphvizInjectionPlanVisitor 033 extends AbstractInjectionPlanNodeVisitor implements EdgeVisitor<InjectionPlan<?>> { 034 /** 035 * Legend for the configuration graph in Graphviz format. 036 */ 037 private static final String LEGEND = 038 " subgraph cluster_legend {\n" 039 + " shape=box;\n" 040 + " label=\"Legend\";\n" 041 + " Constructor [shape=box];\n" 042 + " JavaInstance [shape=box, style=bold];\n" 043 + " Subplan [shape=oval, style=dashed];\n" 044 + " RequiredSingleton [shape=box, style=filled];\n" 045 + " Subplan -> Constructor -> RequiredSingleton -> JavaInstance [style=invis];\n" 046 + " }\n"; 047 048 /** 049 * Accumulate string representation of the graph here. 050 */ 051 private final transient StringBuilder graphStr = 052 new StringBuilder("digraph InjectionPlanMain {\n"); 053 054 /** 055 * Create a new visitor to build a graphviz string for the injection plan. 056 * 057 * @param showLegend if true, show legend on the graph. 058 */ 059 public GraphvizInjectionPlanVisitor(final boolean showLegend) { 060 if (showLegend) { 061 this.graphStr.append(LEGEND); 062 } 063 this.graphStr.append("subgraph cluster_main {\n style=invis;\n"); 064 } 065 066 /** 067 * Produce a Graphviz DOT string for a given TANG injection plan. 068 * 069 * @param injectionPlan TANG injection plan. 070 * @param showLegend if true, show legend on the graph. 071 * @return Injection plan represented as a string in Graphviz DOT format. 072 */ 073 public static String getGraphvizString( 074 final InjectionPlan<?> injectionPlan, final boolean showLegend) { 075 final GraphvizInjectionPlanVisitor visitor = new GraphvizInjectionPlanVisitor(showLegend); 076 Walk.preorder(visitor, visitor, injectionPlan); 077 return visitor.toString(); 078 } 079 080 /** 081 * Process current injection plan node of Constructor type. 082 * 083 * @param node Current injection plan node. 084 * @return true to proceed with the next node, false to cancel. 085 */ 086 @Override 087 public boolean visit(final Constructor<?> node) { 088 this.graphStr 089 .append(" \"") 090 .append(node.getClass()) 091 .append('_') 092 .append(node.getNode().getName()) 093 .append("\" [label=\"") 094 .append(node.getNode().getName()) 095 .append("\", shape=box];\n"); 096 return true; 097 } 098 099 /** 100 * Process current injection plan node of JavaInstance type. 101 * 102 * @param node Current injection plan node. 103 * @return true to proceed with the next node, false to cancel. 104 */ 105 @Override 106 public boolean visit(final JavaInstance<?> node) { 107 this.graphStr 108 .append(" \"") 109 .append(node.getClass()) 110 .append('_') 111 .append(node.getNode().getName()) 112 .append("\" [label=\"") 113 .append(node.getNode().getName()) 114 .append(" = ") 115 .append(node.getInstanceAsString()) 116 .append("\", shape=box, style=bold];\n"); 117 return true; 118 } 119 120 /** 121 * Process current injection plan node of Subplan type. 122 * 123 * @param node Current injection plan node. 124 * @return true to proceed with the next node, false to cancel. 125 */ 126 @Override 127 public boolean visit(final Subplan<?> node) { 128 this.graphStr 129 .append(" \"") 130 .append(node.getClass()) 131 .append('_') 132 .append(node.getNode().getName()) 133 .append("\" [label=\"") 134 .append(node.getNode().getName()) 135 .append("\", shape=oval, style=dashed];\n"); 136 return true; 137 } 138 139 /** 140 * Process current edge of the injection plan. 141 * 142 * @param nodeFrom Current injection plan node. 143 * @param nodeTo Destination injection plan node. 144 * @return true to proceed with the next node, false to cancel. 145 */ 146 @Override 147 public boolean visit(final InjectionPlan<?> nodeFrom, final InjectionPlan<?> nodeTo) { 148 this.graphStr 149 .append(" \"") 150 .append(nodeFrom.getClass()) 151 .append('_') 152 .append(nodeFrom.getNode().getName()) 153 .append("\" -> \"") 154 .append(nodeTo.getClass()) 155 .append('_') 156 .append(nodeTo.getNode().getName()) 157 .append("\" [style=solid];\n"); 158 return true; 159 } 160 161 /** 162 * @return TANG injection plan represented as a Graphviz DOT string. 163 */ 164 @Override 165 public String toString() { 166 return this.graphStr.toString() + "}}\n"; 167 } 168}