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.FromType;
025    import org.apache.camel.model.MulticastType;
026    import org.apache.camel.model.ProcessorType;
027    import org.apache.camel.model.RouteType;
028    import static org.apache.camel.util.ObjectHelper.isNullOrBlank;
029    
030    /**
031     * @version $Revision: 382 $
032     */
033    public class XmlGraphGenerator extends GraphGeneratorSupport {
034        private boolean addUrl = true;
035    
036        public XmlGraphGenerator(String dir) {
037            super(dir, ".xml");
038        }
039    
040        protected void generateFile(PrintWriter writer, Map<String, List<RouteType>> map) {
041            writer.println("<?xml version='1.0' encoding='UTF-8'?>");
042            writer.println("<Graph>");
043            writer.println();
044    
045            if (map.size() > 0) {
046                writer.println("<Node id='root' name='Camel Routes' description='Collection of Camel Routes' nodeType='root'/>");
047            }
048            printRoutes(writer, map);
049    
050            writer.println();
051            writer.println("</Graph>");
052        }
053    
054        protected void printRoutes(PrintWriter writer, Map<String, List<RouteType>> map) {
055            Set<Map.Entry<String, List<RouteType>>> entries = map.entrySet();
056            for (Map.Entry<String, List<RouteType>> entry : entries) {
057                String group = entry.getKey();
058                printRoutes(writer, group, entry.getValue());
059            }
060        }
061    
062        protected void printRoutes(PrintWriter writer, String group, List<RouteType> routes) {
063            group = encode(group);
064            if (group != null) {
065                int idx = group.lastIndexOf('.');
066                String name = group;
067                if (idx > 0 && idx < group.length() - 1) {
068                    name = group.substring(idx + 1);
069                }
070                writer.println("<Node id='" + group + "' name='" + name + "' description='" + group + "' nodeType='group'/>");
071                writer.println("<Edge fromID='root' toID='" + group + "'/>");
072            }
073            for (RouteType route : routes) {
074                List<FromType> inputs = route.getInputs();
075                boolean first = true;
076                for (FromType input : inputs) {
077                    NodeData nodeData = getNodeData(input);
078                    if (first) {
079                        first = false;
080                        if (group != null) {
081                            writer.println("<Edge fromID='" + group + "' toID='" + encode(nodeData.id) + "'/>");
082                        }
083                    }
084                    printRoute(writer, route, nodeData);
085                }
086                writer.println();
087            }
088        }
089    
090        protected void printRoute(PrintWriter writer, final RouteType route, NodeData nodeData) {
091            printNode(writer, nodeData);
092    
093            // TODO we should add a transactional client / event driven consumer / polling client
094    
095            NodeData from = nodeData;
096            for (ProcessorType output : route.getOutputs()) {
097                NodeData newData = printNode(writer, from, output);
098                from = newData;
099            }
100        }
101    
102        protected NodeData printNode(PrintWriter writer, NodeData fromData, ProcessorType node) {
103            if (node instanceof MulticastType) {
104                // no need for a multicast node
105                List<ProcessorType> outputs = node.getOutputs();
106                for (ProcessorType output : outputs) {
107                    printNode(writer, fromData, output);
108                }
109                return fromData;
110            }
111            NodeData toData = getNodeData(node);
112    
113            printNode(writer, toData);
114    
115            if (fromData != null) {
116                writer.print("<Edge fromID=\"");
117                writer.print(encode(fromData.id));
118                writer.print("\" toID=\"");
119                writer.print(encode(toData.id));
120                String association = toData.edgeLabel;
121                if (isNullOrBlank(association)) {
122                    writer.print("\" association=\"");
123                    writer.print(encode(association));
124                }
125                writer.println("\"/>");
126            }
127    
128            // now lets write any children
129            List<ProcessorType> outputs = toData.outputs;
130            if (outputs != null) {
131                for (ProcessorType output : outputs) {
132                    NodeData newData = printNode(writer, toData, output);
133                    if (!isMulticastNode(node)) {
134                        toData = newData;
135                    }
136                }
137            }
138            return toData;
139        }
140    
141        protected void printNode(PrintWriter writer, NodeData data) {
142            if (!data.nodeWritten) {
143                data.nodeWritten = true;
144    
145                writer.println();
146                writer.print("<Node id=\"");
147                writer.print(encode(data.id));
148                writer.print("\" name=\"");
149                String name = data.label;
150                if (isNullOrBlank(name)) {
151                    name = data.tooltop;
152                }
153                writer.print(encode(name));
154                writer.print("\" nodeType=\"");
155                String nodeType = data.image;
156                if (isNullOrBlank(nodeType)) {
157                    nodeType = data.shape;
158                    if (isNullOrBlank(nodeType)) {
159                        nodeType = "node";
160                    }
161                }
162                writer.print(encode(nodeType));
163                writer.print("\" description=\"");
164                writer.print(encode(data.tooltop));
165                if (addUrl) {
166                    writer.print("\" url=\"");
167                    writer.print(encode(data.url));
168                }
169                writer.println("\"/>");
170            }
171        }
172    
173        protected String encode(String text) {
174            if (text == null) {
175                return "";
176            }
177            return text.replaceAll("\"", "&quot;").replaceAll("<", "&lt;").
178                    replaceAll(">", "&gt;").replaceAll("&", "&amp;");
179        }
180    }