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.servicemix.jbi.view;
018
019 import java.io.PrintWriter;
020 import java.util.ArrayList;
021 import java.util.Collection;
022 import java.util.List;
023 import java.util.Map;
024 import java.util.Set;
025 import java.util.concurrent.ConcurrentHashMap;
026 import java.util.concurrent.CopyOnWriteArraySet;
027
028 import javax.jbi.messaging.MessageExchange;
029 import javax.jbi.servicedesc.ServiceEndpoint;
030
031 import org.apache.servicemix.JbiConstants;
032 import org.apache.servicemix.jbi.event.ComponentEvent;
033 import org.apache.servicemix.jbi.event.ComponentListener;
034 import org.apache.servicemix.jbi.event.EndpointEvent;
035 import org.apache.servicemix.jbi.event.ExchangeEvent;
036 import org.apache.servicemix.jbi.event.ExchangeListener;
037 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
038 import org.apache.servicemix.jbi.framework.Registry;
039 import org.apache.servicemix.jbi.messaging.MessageExchangeImpl;
040 import org.apache.servicemix.jbi.servicedesc.AbstractServiceEndpoint;
041 import org.apache.servicemix.jbi.servicedesc.EndpointSupport;
042
043 /**
044 * Creates a <a href="http://www.graphviz.org/">DOT</a> file showing the JBI MessageExchange
045 * flow within the JBI Container.
046
047 * @org.apache.xbean.XBean
048 * description="Generates DOT visualisations of the exchanges flow inside ServiceMix"
049 *
050 * @version $Revision: 391707 $
051 */
052 public class DotViewFlowListener extends DotViewEndpointListener
053 implements ExchangeListener, ComponentListener {
054
055 private Map<String, Map<String, Boolean>> flow;
056 private Set<String> flowLinks;
057 private Set<String> usedComponents;
058 private Set<String> componentsAsConsumer;
059 private boolean displayComponents = true;
060
061 public DotViewFlowListener() {
062 setFile("ServiceMixFlow.dot");
063 flow = new ConcurrentHashMap<String, Map<String, Boolean>>();
064 flowLinks = new CopyOnWriteArraySet<String>();
065 usedComponents = new CopyOnWriteArraySet<String>();
066 componentsAsConsumer = new CopyOnWriteArraySet<String>();
067 }
068
069 // Implementation methods
070 // -------------------------------------------------------------------------
071
072 protected void generateFile(PrintWriter writer) throws Exception {
073 writer.println("digraph \"Apache ServiceMix\" {");
074 writer.println();
075 writer.println("label = \"Apache ServiceMix flow\";");
076 writer.println("node [ shape = box, style = \"rounded,filled\", fontname = \"Helvetica-Oblique\", fontsize = 8 ];");
077 writer.println();
078
079 List<String> brokerLinks = new ArrayList<String>();
080 Registry registry = getContainer().getRegistry();
081 Collection<ComponentMBeanImpl> components = registry.getComponents();
082 for (ComponentMBeanImpl component : components) {
083 ServiceEndpoint[] ses = registry.getEndpointRegistry().getAllEndpointsForComponent(component.getComponentNameSpace());
084 String name = component.getName();
085 if (!usedComponents.contains(name)) {
086 continue;
087 }
088 // If we want to display components, create
089 // a sub graph, grouping all the components
090 // endpoints
091 if (isDisplayComponents()) {
092 String id = encode(name);
093 writer.println("subgraph cluster_" + id + " {");
094 writer.println(" label=\"" + name + "\";");
095 if (componentsAsConsumer.contains(name)) {
096 writer.println(" " + id + " [ fillcolor = gray, label = \"" + name + "\" ];");
097 }
098 }
099 for (int i = 0; i < ses.length; i++) {
100 String key = EndpointSupport.getUniqueKey(ses[i]);
101 String epname = formatEndpoint(key);
102 if (!isDisplayComponents()) {
103 epname += "\\n" + name;
104 }
105 String color = "lightgray";
106 if (epname.startsWith("internal")) {
107 epname = epname.substring(10);
108 color = "#6699ff";
109 } else if (epname.startsWith("external")) {
110 epname = epname.substring(10);
111 color = "#66ccff";
112 } else if (epname.startsWith("dynamic")) {
113 epname = epname.substring(9);
114 color = "#6666ff";
115 } else if (epname.startsWith("linked")) {
116 epname = epname.substring(8);
117 color = "#66ffff";
118 } else {
119 color = "#f3f3f3";
120 }
121 String epid = encode(key);
122 writer.println(" " + epid + " [fillcolor = \"" + color + "\", label=\"" + epname + "\"];");
123 }
124 if (isDisplayComponents()) {
125 writer.println("}");
126 }
127 }
128 writer.println();
129 generateLinks(writer, brokerLinks);
130
131 writer.println();
132
133 generateLinks(writer, flowLinks);
134
135 writer.println("}");
136 }
137
138 public void exchangeSent(ExchangeEvent event) {
139 MessageExchange me = event.getExchange();
140 if (me.getEndpoint() instanceof AbstractServiceEndpoint && me instanceof MessageExchangeImpl) {
141 MessageExchangeImpl mei = (MessageExchangeImpl) me;
142 String source = (String) me.getProperty(JbiConstants.SENDER_ENDPOINT);
143 if (source == null) {
144 source = mei.getSourceId().getName();
145 componentsAsConsumer.add(source);
146 } else {
147 ServiceEndpoint[] ses = getContainer().getRegistry().getEndpointRegistry().getAllEndpointsForComponent(mei.getSourceId());
148 for (int i = 0; i < ses.length; i++) {
149 if (EndpointSupport.getKey(ses[i]).equals(source)) {
150 source = EndpointSupport.getUniqueKey(ses[i]);
151 break;
152 }
153 }
154 }
155 usedComponents.add(mei.getSourceId().getName());
156 if (((AbstractServiceEndpoint) mei.getEndpoint()).getComponentNameSpace() != null) {
157 usedComponents.add(((AbstractServiceEndpoint) mei.getEndpoint()).getComponentNameSpace().getName());
158 }
159 String dest = EndpointSupport.getUniqueKey(mei.getEndpoint());
160 Map<String, Boolean> componentFlow = createSource(source);
161 if (componentFlow.put(dest, Boolean.TRUE) == null) {
162 flowLinks.add(encode(source) + " -> " + encode(dest));
163 viewIsDirty(mei.getEndpoint());
164 }
165 }
166 }
167
168 public void exchangeAccepted(ExchangeEvent event) {
169 }
170
171 protected Map<String, Boolean> createSource(String name) {
172 synchronized (flow) {
173 Map<String, Boolean> componentFlow = flow.get(name);
174 if (componentFlow == null) {
175 componentFlow = new ConcurrentHashMap<String, Boolean>();
176 flow.put(name, componentFlow);
177 }
178 return componentFlow;
179 }
180 }
181
182 public void internalEndpointRegistered(EndpointEvent event) {
183 String key = EndpointSupport.getUniqueKey(event.getEndpoint());
184 createSource(key);
185 super.internalEndpointRegistered(event);
186 }
187
188 public void externalEndpointRegistered(EndpointEvent event) {
189 String key = EndpointSupport.getUniqueKey(event.getEndpoint());
190 createSource(key);
191 super.externalEndpointRegistered(event);
192 }
193
194 public void linkedEndpointRegistered(EndpointEvent event) {
195 String key = EndpointSupport.getUniqueKey(event.getEndpoint());
196 createSource(key);
197 super.linkedEndpointRegistered(event);
198 }
199
200 public void componentInstalled(ComponentEvent event) {
201 createSource(event.getComponent().getName());
202 }
203
204 public void componentInitialized(ComponentEvent event) {
205 createSource(event.getComponent().getName());
206 }
207
208 public void componentStarted(ComponentEvent event) {
209 }
210
211 public void componentStopped(ComponentEvent event) {
212 }
213
214 public void componentShutDown(ComponentEvent event) {
215 }
216
217 public void componentUninstalled(ComponentEvent event) {
218 }
219
220 public boolean isDisplayComponents() {
221 return displayComponents;
222 }
223
224 public void setDisplayComponents(boolean displayComponents) {
225 this.displayComponents = displayComponents;
226 }
227
228 }