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 }