/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.servicemix.jbi.view;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.servicedesc.ServiceEndpoint;
import org.apache.servicemix.JbiConstants;
import org.apache.servicemix.jbi.event.ComponentEvent;
import org.apache.servicemix.jbi.event.ComponentListener;
import org.apache.servicemix.jbi.event.EndpointEvent;
import org.apache.servicemix.jbi.event.ExchangeEvent;
import org.apache.servicemix.jbi.event.ExchangeListener;
import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
import org.apache.servicemix.jbi.framework.Registry;
import org.apache.servicemix.jbi.messaging.MessageExchangeImpl;
import org.apache.servicemix.jbi.servicedesc.AbstractServiceEndpoint;
import org.apache.servicemix.jbi.servicedesc.EndpointSupport;
/**
* Creates a <a href="http://www.graphviz.org/">DOT</a> file showing the JBI MessageExchange
* flow within the JBI Container.
* @org.apache.xbean.XBean
* description="Generates DOT visualisations of the exchanges flow inside ServiceMix"
*
* @version $Revision: 391707 $
*/
public class DotViewFlowListener extends DotViewEndpointListener
implements ExchangeListener, ComponentListener {
private Map<String, Map<String, Boolean>> flow;
private Set<String> flowLinks;
private Set<String> usedComponents;
private Set<String> componentsAsConsumer;
private boolean displayComponents = true;
public DotViewFlowListener() {
setFile("ServiceMixFlow.dot");
flow = new ConcurrentHashMap<String, Map<String, Boolean>>();
flowLinks = new CopyOnWriteArraySet<String>();
usedComponents = new CopyOnWriteArraySet<String>();
componentsAsConsumer = new CopyOnWriteArraySet<String>();
}
// Implementation methods
// -------------------------------------------------------------------------
protected void generateFile(PrintWriter writer) throws Exception {
writer.println("digraph \"Apache ServiceMix\" {");
writer.println();
writer.println("label = \"Apache ServiceMix flow\";");
writer.println("node [ shape = box, style = \"rounded,filled\", fontname = \"Helvetica-Oblique\", fontsize = 8 ];");
writer.println();
List<String> brokerLinks = new ArrayList<String>();
Registry registry = getContainer().getRegistry();
Collection<ComponentMBeanImpl> components = registry.getComponents();
for (ComponentMBeanImpl component : components) {
ServiceEndpoint[] ses = registry.getEndpointRegistry().getAllEndpointsForComponent(component.getComponentNameSpace());
String name = component.getName();
if (!usedComponents.contains(name)) {
continue;
}
// If we want to display components, create
// a sub graph, grouping all the components
// endpoints
if (isDisplayComponents()) {
String id = encode(name);
writer.println("subgraph cluster_" + id + " {");
writer.println(" label=\"" + name + "\";");
if (componentsAsConsumer.contains(name)) {
writer.println(" " + id + " [ fillcolor = gray, label = \"" + name + "\" ];");
}
}
for (int i = 0; i < ses.length; i++) {
String key = EndpointSupport.getUniqueKey(ses[i]);
String epname = formatEndpoint(key);
if (!isDisplayComponents()) {
epname += "\\n" + name;
}
String color = "lightgray";
if (epname.startsWith("internal")) {
epname = epname.substring(10);
color = "#6699ff";
} else if (epname.startsWith("external")) {
epname = epname.substring(10);
color = "#66ccff";
} else if (epname.startsWith("dynamic")) {
epname = epname.substring(9);
color = "#6666ff";
} else if (epname.startsWith("linked")) {
epname = epname.substring(8);
color = "#66ffff";
} else {
color = "#f3f3f3";
}
String epid = encode(key);
writer.println(" " + epid + " [fillcolor = \"" + color + "\", label=\"" + epname + "\"];");
}
if (isDisplayComponents()) {
writer.println("}");
}
}
writer.println();
generateLinks(writer, brokerLinks);
writer.println();
generateLinks(writer, flowLinks);
writer.println("}");
}
public void exchangeSent(ExchangeEvent event) {
MessageExchange me = event.getExchange();
if (me.getEndpoint() instanceof AbstractServiceEndpoint && me instanceof MessageExchangeImpl) {
MessageExchangeImpl mei = (MessageExchangeImpl) me;
String source = (String) me.getProperty(JbiConstants.SENDER_ENDPOINT);
if (source == null) {
source = mei.getSourceId().getName();
componentsAsConsumer.add(source);
} else {
ServiceEndpoint[] ses = getContainer().getRegistry().getEndpointRegistry().getAllEndpointsForComponent(mei.getSourceId());
for (int i = 0; i < ses.length; i++) {
if (EndpointSupport.getKey(ses[i]).equals(source)) {
source = EndpointSupport.getUniqueKey(ses[i]);
break;
}
}
}
usedComponents.add(mei.getSourceId().getName());
if (((AbstractServiceEndpoint) mei.getEndpoint()).getComponentNameSpace() != null) {
usedComponents.add(((AbstractServiceEndpoint) mei.getEndpoint()).getComponentNameSpace().getName());
}
String dest = EndpointSupport.getUniqueKey(mei.getEndpoint());
Map<String, Boolean> componentFlow = createSource(source);
if (componentFlow.put(dest, Boolean.TRUE) == null) {
flowLinks.add(encode(source) + " -> " + encode(dest));
viewIsDirty(mei.getEndpoint());
}
}
}
public void exchangeAccepted(ExchangeEvent event) {
}
protected Map<String, Boolean> createSource(String name) {
synchronized (flow) {
Map<String, Boolean> componentFlow = flow.get(name);
if (componentFlow == null) {
componentFlow = new ConcurrentHashMap<String, Boolean>();
flow.put(name, componentFlow);
}
return componentFlow;
}
}
public void internalEndpointRegistered(EndpointEvent event) {
String key = EndpointSupport.getUniqueKey(event.getEndpoint());
createSource(key);
super.internalEndpointRegistered(event);
}
public void externalEndpointRegistered(EndpointEvent event) {
String key = EndpointSupport.getUniqueKey(event.getEndpoint());
createSource(key);
super.externalEndpointRegistered(event);
}
public void linkedEndpointRegistered(EndpointEvent event) {
String key = EndpointSupport.getUniqueKey(event.getEndpoint());
createSource(key);
super.linkedEndpointRegistered(event);
}
public void componentInstalled(ComponentEvent event) {
createSource(event.getComponent().getName());
}
public void componentInitialized(ComponentEvent event) {
createSource(event.getComponent().getName());
}
public void componentStarted(ComponentEvent event) {
}
public void componentStopped(ComponentEvent event) {
}
public void componentShutDown(ComponentEvent event) {
}
public void componentUninstalled(ComponentEvent event) {
}
public boolean isDisplayComponents() {
return displayComponents;
}
public void setDisplayComponents(boolean displayComponents) {
this.displayComponents = displayComponents;
}
}