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.isEmpty;
029
030 /**
031 * @version $Revision: 750806 $
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<RouteDefinition>> 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<RouteDefinition>> map) {
055 Set<Map.Entry<String, List<RouteDefinition>>> entries = map.entrySet();
056 for (Map.Entry<String, List<RouteDefinition>> 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<RouteDefinition> 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 (RouteDefinition route : routes) {
074 List<FromDefinition> inputs = route.getInputs();
075 boolean first = true;
076 for (FromDefinition 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 RouteDefinition 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 (ProcessorDefinition output : route.getOutputs()) {
097 NodeData newData = printNode(writer, from, output);
098 from = newData;
099 }
100 }
101
102 @SuppressWarnings("unchecked")
103 protected NodeData printNode(PrintWriter writer, NodeData fromData, ProcessorDefinition node) {
104 if (node instanceof MulticastDefinition) {
105 // no need for a multicast node
106 List<ProcessorDefinition> outputs = node.getOutputs();
107 for (ProcessorDefinition output : outputs) {
108 printNode(writer, fromData, output);
109 }
110 return fromData;
111 }
112 NodeData toData = getNodeData(node);
113
114 printNode(writer, toData);
115
116 if (fromData != null) {
117 writer.print("<Edge fromID=\"");
118 writer.print(encode(fromData.id));
119 writer.print("\" toID=\"");
120 writer.print(encode(toData.id));
121 String association = toData.edgeLabel;
122 if (isEmpty(association)) {
123 writer.print("\" association=\"");
124 writer.print(encode(association));
125 }
126 writer.println("\"/>");
127 }
128
129 // now lets write any children
130 List<ProcessorDefinition> outputs = toData.outputs;
131 if (outputs != null) {
132 for (ProcessorDefinition output : outputs) {
133 NodeData newData = printNode(writer, toData, output);
134 if (!isMulticastNode(node)) {
135 toData = newData;
136 }
137 }
138 }
139 return toData;
140 }
141
142 protected void printNode(PrintWriter writer, NodeData data) {
143 if (!data.nodeWritten) {
144 data.nodeWritten = true;
145
146 writer.println();
147 writer.print("<Node id=\"");
148 writer.print(encode(data.id));
149 writer.print("\" name=\"");
150 String name = data.label;
151 if (isEmpty(name)) {
152 name = data.tooltop;
153 }
154 writer.print(encode(name));
155 writer.print("\" nodeType=\"");
156 String nodeType = data.image;
157 if (isEmpty(nodeType)) {
158 nodeType = data.shape;
159 if (isEmpty(nodeType)) {
160 nodeType = "node";
161 }
162 }
163 writer.print(encode(nodeType));
164 writer.print("\" description=\"");
165 writer.print(encode(data.tooltop));
166 if (addUrl) {
167 writer.print("\" url=\"");
168 writer.print(encode(data.url));
169 }
170 writer.println("\"/>");
171 }
172 }
173
174 protected String encode(String text) {
175 if (text == null) {
176 return "";
177 }
178 return text.replaceAll("\"", """).replaceAll("<", "<").
179 replaceAll(">", ">").replaceAll("&", "&");
180 }
181 }