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.activemq.broker.view; 018 019 import org.apache.activemq.broker.Broker; 020 import org.apache.activemq.broker.ConnectionContext; 021 import org.apache.activemq.broker.ProducerBrokerExchange; 022 import org.apache.activemq.broker.jmx.BrokerViewMBean; 023 import org.apache.activemq.broker.jmx.SubscriptionViewMBean; 024 import org.apache.activemq.broker.region.Subscription; 025 import org.apache.activemq.command.ActiveMQDestination; 026 import org.apache.activemq.command.ConsumerInfo; 027 import org.apache.activemq.command.Message; 028 import org.apache.activemq.command.ProducerId; 029 import org.apache.activemq.command.ProducerInfo; 030 import org.apache.activemq.filter.DestinationMapNode; 031 import java.io.IOException; 032 import java.io.PrintWriter; 033 import java.util.Collection; 034 import java.util.HashMap; 035 import java.util.HashSet; 036 import java.util.Iterator; 037 import java.util.Map; 038 import java.util.Set; 039 import javax.management.ObjectName; 040 041 /** 042 * 043 */ 044 public class ConnectionDotFileInterceptor extends DotFileInterceptorSupport { 045 046 protected static final String ID_SEPARATOR = "_"; 047 048 private final boolean redrawOnRemove; 049 private boolean clearProducerCacheAfterRender; 050 private String domain = "org.apache.activemq"; 051 private BrokerViewMBean brokerView; 052 053 // until we have some MBeans for producers, lets do it all ourselves 054 private Map<ProducerId, ProducerInfo> producers = new HashMap<ProducerId, ProducerInfo>(); 055 private Map<ProducerId, Set<ActiveMQDestination>> producerDestinations = new HashMap<ProducerId, Set<ActiveMQDestination>>(); 056 private Object lock = new Object(); 057 058 public ConnectionDotFileInterceptor(Broker next, String file, boolean redrawOnRemove) throws IOException { 059 super(next, file); 060 this.redrawOnRemove = redrawOnRemove; 061 062 } 063 064 public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 065 Subscription answer = super.addConsumer(context, info); 066 generateFile(); 067 return answer; 068 } 069 070 public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { 071 super.addProducer(context, info); 072 ProducerId producerId = info.getProducerId(); 073 synchronized (lock) { 074 producers.put(producerId, info); 075 } 076 generateFile(); 077 } 078 079 public void removeConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 080 super.removeConsumer(context, info); 081 if (redrawOnRemove) { 082 generateFile(); 083 } 084 } 085 086 public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception { 087 super.removeProducer(context, info); 088 ProducerId producerId = info.getProducerId(); 089 if (redrawOnRemove) { 090 synchronized (lock) { 091 producerDestinations.remove(producerId); 092 producers.remove(producerId); 093 } 094 generateFile(); 095 } 096 } 097 098 public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception { 099 super.send(producerExchange, messageSend); 100 ProducerId producerId = messageSend.getProducerId(); 101 ActiveMQDestination destination = messageSend.getDestination(); 102 synchronized (lock) { 103 Set<ActiveMQDestination> destinations = producerDestinations.get(producerId); 104 if (destinations == null) { 105 destinations = new HashSet<ActiveMQDestination>(); 106 } 107 producerDestinations.put(producerId, destinations); 108 destinations.add(destination); 109 } 110 } 111 112 protected void generateFile(PrintWriter writer) throws Exception { 113 114 writer.println("digraph \"ActiveMQ Connections\" {"); 115 writer.println(); 116 writer.println("label=\"ActiveMQ Broker: " + getBrokerView().getBrokerId() + "\"];"); 117 writer.println(); 118 writer.println("node [style = \"rounded,filled\", fillcolor = yellow, fontname=\"Helvetica-Oblique\"];"); 119 writer.println(); 120 121 Map<String, String> clients = new HashMap<String, String>(); 122 Map<String, String> queues = new HashMap<String, String>(); 123 Map<String, String> topics = new HashMap<String, String>(); 124 125 printSubscribers(writer, clients, queues, "queue_", getBrokerView().getQueueSubscribers()); 126 writer.println(); 127 128 printSubscribers(writer, clients, topics, "topic_", getBrokerView().getTopicSubscribers()); 129 writer.println(); 130 131 printProducers(writer, clients, queues, topics); 132 writer.println(); 133 134 writeLabels(writer, "green", "Client: ", clients); 135 writer.println(); 136 137 writeLabels(writer, "red", "Queue: ", queues); 138 writeLabels(writer, "blue", "Topic: ", topics); 139 writer.println("}"); 140 141 if (clearProducerCacheAfterRender) { 142 producerDestinations.clear(); 143 } 144 } 145 146 protected void printProducers(PrintWriter writer, Map<String, String> clients, Map<String, String> queues, Map<String, String> topics) { 147 synchronized (lock) { 148 for (Iterator iter = producerDestinations.entrySet().iterator(); iter.hasNext();) { 149 Map.Entry entry = (Map.Entry)iter.next(); 150 ProducerId producerId = (ProducerId)entry.getKey(); 151 Set destinationSet = (Set)entry.getValue(); 152 printProducers(writer, clients, queues, topics, producerId, destinationSet); 153 } 154 } 155 } 156 157 protected void printProducers(PrintWriter writer, Map<String, String> clients, Map<String, String> queues, Map<String, String> topics, ProducerId producerId, Set destinationSet) { 158 for (Iterator iter = destinationSet.iterator(); iter.hasNext();) { 159 ActiveMQDestination destination = (ActiveMQDestination)iter.next(); 160 161 // TODO use clientId one day 162 String clientId = producerId.getConnectionId(); 163 String safeClientId = asID(clientId); 164 clients.put(safeClientId, clientId); 165 166 String physicalName = destination.getPhysicalName(); 167 String safeDestinationId = asID(physicalName); 168 if (destination.isTopic()) { 169 safeDestinationId = "topic_" + safeDestinationId; 170 topics.put(safeDestinationId, physicalName); 171 } else { 172 safeDestinationId = "queue_" + safeDestinationId; 173 queues.put(safeDestinationId, physicalName); 174 } 175 176 String safeProducerId = asID(producerId.toString()); 177 178 // lets write out the links 179 180 writer.print(safeClientId); 181 writer.print(" -> "); 182 writer.print(safeProducerId); 183 writer.println(";"); 184 185 writer.print(safeProducerId); 186 writer.print(" -> "); 187 writer.print(safeDestinationId); 188 writer.println(";"); 189 190 // now lets write out the label 191 writer.print(safeProducerId); 192 writer.print(" [label = \""); 193 String label = "Producer: " + producerId.getSessionId() + "-" + producerId.getValue(); 194 writer.print(label); 195 writer.println("\"];"); 196 197 } 198 } 199 200 protected void printSubscribers(PrintWriter writer, Map<String, String> clients, Map<String, String> destinations, String type, ObjectName[] subscribers) { 201 for (int i = 0; i < subscribers.length; i++) { 202 ObjectName name = subscribers[i]; 203 SubscriptionViewMBean subscriber = (SubscriptionViewMBean)getBrokerService().getManagementContext().newProxyInstance(name, SubscriptionViewMBean.class, true); 204 205 String clientId = subscriber.getClientId(); 206 String safeClientId = asID(clientId); 207 clients.put(safeClientId, clientId); 208 209 String destination = subscriber.getDestinationName(); 210 String safeDestinationId = type + asID(destination); 211 destinations.put(safeDestinationId, destination); 212 213 String selector = subscriber.getSelector(); 214 215 // lets write out the links 216 String subscriberId = safeClientId + "_" + subscriber.getSessionId() + "_" + subscriber.getSubcriptionId(); 217 218 writer.print(subscriberId); 219 writer.print(" -> "); 220 writer.print(safeClientId); 221 writer.println(";"); 222 223 writer.print(safeDestinationId); 224 writer.print(" -> "); 225 writer.print(subscriberId); 226 writer.println(";"); 227 228 // now lets write out the label 229 writer.print(subscriberId); 230 writer.print(" [label = \""); 231 String label = "Subscription: " + subscriber.getSessionId() + "-" + subscriber.getSubcriptionId(); 232 if (selector != null && selector.length() > 0) { 233 label = label + "\\nSelector: " + selector; 234 } 235 writer.print(label); 236 writer.println("\"];"); 237 } 238 } 239 240 protected void writeLabels(PrintWriter writer, String color, String prefix, Map<String, String> map) { 241 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) { 242 Map.Entry entry = (Map.Entry)iter.next(); 243 String id = (String)entry.getKey(); 244 String label = (String)entry.getValue(); 245 246 writer.print(id); 247 writer.print(" [ fillcolor = "); 248 writer.print(color); 249 writer.print(", label = \""); 250 writer.print(prefix); 251 writer.print(label); 252 writer.println("\"];"); 253 } 254 } 255 256 /** 257 * Lets strip out any non supported characters 258 */ 259 protected String asID(String name) { 260 StringBuffer buffer = new StringBuffer(); 261 int size = name.length(); 262 for (int i = 0; i < size; i++) { 263 char ch = name.charAt(i); 264 if (Character.isLetterOrDigit(ch) || ch == '_') { 265 buffer.append(ch); 266 } else { 267 buffer.append('_'); 268 } 269 } 270 return buffer.toString(); 271 } 272 273 protected void printNodes(PrintWriter writer, DestinationMapNode node, String prefix) { 274 String path = getPath(node); 275 writer.print(" "); 276 writer.print(prefix); 277 writer.print(ID_SEPARATOR); 278 writer.print(path); 279 String label = path; 280 if (prefix.equals("topic")) { 281 label = "Topics"; 282 } else if (prefix.equals("queue")) { 283 label = "Queues"; 284 } 285 writer.print("[ label = \""); 286 writer.print(label); 287 writer.println("\" ];"); 288 289 Collection children = node.getChildren(); 290 for (Iterator iter = children.iterator(); iter.hasNext();) { 291 DestinationMapNode child = (DestinationMapNode)iter.next(); 292 printNodes(writer, child, prefix + ID_SEPARATOR + path); 293 } 294 } 295 296 protected void printNodeLinks(PrintWriter writer, DestinationMapNode node, String prefix) { 297 String path = getPath(node); 298 Collection children = node.getChildren(); 299 for (Iterator iter = children.iterator(); iter.hasNext();) { 300 DestinationMapNode child = (DestinationMapNode)iter.next(); 301 302 writer.print(" "); 303 writer.print(prefix); 304 writer.print(ID_SEPARATOR); 305 writer.print(path); 306 writer.print(" -> "); 307 writer.print(prefix); 308 writer.print(ID_SEPARATOR); 309 writer.print(path); 310 writer.print(ID_SEPARATOR); 311 writer.print(getPath(child)); 312 writer.println(";"); 313 314 printNodeLinks(writer, child, prefix + ID_SEPARATOR + path); 315 } 316 } 317 318 protected String getPath(DestinationMapNode node) { 319 String path = node.getPath(); 320 if (path.equals("*")) { 321 return "root"; 322 } 323 return path; 324 } 325 326 BrokerViewMBean getBrokerView() throws Exception { 327 if (this.brokerView == null) { 328 ObjectName brokerName = getBrokerService().getBrokerObjectName(); 329 this.brokerView = (BrokerViewMBean) getBrokerService().getManagementContext().newProxyInstance(brokerName, 330 BrokerViewMBean.class, true); 331 } 332 return this.brokerView; 333 } 334 }