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    }