001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.view;
018
019 import java.io.PrintWriter;
020 import java.util.List;
021 import java.util.Map;
022 import java.util.Set;
023
024 import org.apache.camel.model.FromDefinition;
025 import org.apache.camel.model.MulticastDefinition;
026 import org.apache.camel.model.ProcessorDefinition;
027 import org.apache.camel.model.RouteDefinition;
028 import static org.apache.camel.util.ObjectHelper.isNotEmpty;
029 /**
030 * A <a href="http://www.graphviz.org/">DOT</a> file creator plugin which
031 * creates a DOT file showing the current routes
032 *
033 * @version
034 */
035 public class RouteDotGenerator extends GraphGeneratorSupport {
036
037 public RouteDotGenerator(String dir) {
038 super(dir, ".dot");
039 }
040
041 // Implementation methods
042 //-------------------------------------------------------------------------
043
044 protected void printRoutes(PrintWriter writer, Map<String, List<RouteDefinition>> map) {
045 Set<Map.Entry<String, List<RouteDefinition>>> entries = map.entrySet();
046 for (Map.Entry<String, List<RouteDefinition>> entry : entries) {
047 String group = entry.getKey();
048 printRoutes(writer, group, entry.getValue());
049 }
050 }
051
052 protected void printRoutes(PrintWriter writer, String group, List<RouteDefinition> routes) {
053 if (group != null) {
054 writer.println("subgraph cluster_" + (clusterCounter++) + " {");
055 writer.println("label = \"" + group + "\";");
056 writer.println("color = grey;");
057 writer.println("style = \"dashed\";");
058 writer.println("URL = \"" + group + ".html\";");
059 writer.println();
060 }
061 for (RouteDefinition route : routes) {
062 List<FromDefinition> inputs = route.getInputs();
063 for (FromDefinition input : inputs) {
064 printRoute(writer, route, input);
065 }
066 writer.println();
067 }
068 if (group != null) {
069 writer.println("}");
070 writer.println();
071 }
072 }
073
074 protected void printRoute(PrintWriter writer, final RouteDefinition route, FromDefinition input) {
075 NodeData nodeData = getNodeData(input);
076
077 printNode(writer, nodeData);
078
079 NodeData from = nodeData;
080 for (ProcessorDefinition<?> output : route.getOutputs()) {
081 NodeData newData = printNode(writer, from, output);
082 from = newData;
083 }
084 }
085
086 protected NodeData printNode(PrintWriter writer, NodeData fromData, ProcessorDefinition<?> node) {
087 if (node instanceof MulticastDefinition) {
088 // no need for a multicast or interceptor node
089 List<ProcessorDefinition<?>> outputs = node.getOutputs();
090 boolean isPipeline = isPipeline(node);
091 for (ProcessorDefinition<?> output : outputs) {
092 NodeData out = printNode(writer, fromData, output);
093 // if in pipeline then we should move the from node to the next in the pipeline
094 if (isPipeline) {
095 fromData = out;
096 }
097 }
098 return fromData;
099 }
100 NodeData toData = getNodeData(node);
101
102 printNode(writer, toData);
103
104 if (fromData != null) {
105 writer.print(fromData.id);
106 writer.print(" -> ");
107 writer.print(toData.id);
108 writer.println(" [");
109
110 String label = fromData.edgeLabel;
111 if (isNotEmpty(label)) {
112 writer.println("label = \"" + label + "\"");
113 }
114 writer.println("];");
115 }
116
117 // now lets write any children
118 List<ProcessorDefinition<?>> outputs = toData.outputs;
119 if (outputs != null) {
120 for (ProcessorDefinition<?> output : outputs) {
121 NodeData newData = printNode(writer, toData, output);
122 if (!isMulticastNode(node)) {
123 toData = newData;
124 }
125 }
126 }
127 return toData;
128 }
129
130 protected void printNode(PrintWriter writer, NodeData data) {
131 if (!data.nodeWritten) {
132 data.nodeWritten = true;
133
134 writer.println();
135 writer.print(data.id);
136 writer.println(" [");
137 writer.println("label = \"" + data.label + "\"");
138 writer.println("tooltip = \"" + data.tooltop + "\"");
139 if (data.url != null) {
140 writer.println("URL = \"" + data.url + "\"");
141 }
142
143 String image = data.image;
144 if (image != null) {
145 writer.println("shapefile = \"" + image + "\"");
146 writer.println("peripheries=0");
147 }
148 String shape = data.shape;
149 if (shape == null && image != null) {
150 shape = "custom";
151 }
152 if (shape != null) {
153 writer.println("shape = \"" + shape + "\"");
154 }
155 writer.println("];");
156 writer.println();
157 }
158 }
159
160 protected void generateFile(PrintWriter writer, Map<String, List<RouteDefinition>> map) {
161 writer.println("digraph CamelRoutes {");
162 writer.println();
163
164 writer.println("node [style = \"rounded,filled\", fillcolor = yellow, "
165 + "fontname=\"Helvetica-Oblique\"];");
166 writer.println();
167 printRoutes(writer, map);
168
169 writer.println("}");
170 }
171
172
173 }