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 */ 017package org.apache.activemq.broker.jmx; 018 019import java.io.IOException; 020import java.util.*; 021import java.util.Map.Entry; 022import java.util.concurrent.ConcurrentHashMap; 023import java.util.concurrent.CopyOnWriteArraySet; 024import java.util.concurrent.ExecutorService; 025import java.util.concurrent.ThreadPoolExecutor; 026 027import javax.jms.IllegalStateException; 028import javax.jms.JMSException; 029import javax.management.InstanceNotFoundException; 030import javax.management.MalformedObjectNameException; 031import javax.management.ObjectName; 032import javax.management.openmbean.CompositeData; 033import javax.management.openmbean.CompositeDataSupport; 034import javax.management.openmbean.CompositeType; 035import javax.management.openmbean.OpenDataException; 036import javax.management.openmbean.TabularData; 037import javax.management.openmbean.TabularDataSupport; 038import javax.management.openmbean.TabularType; 039 040import org.apache.activemq.broker.Broker; 041import org.apache.activemq.broker.BrokerService; 042import org.apache.activemq.broker.ConnectionContext; 043import org.apache.activemq.broker.ProducerBrokerExchange; 044import org.apache.activemq.broker.jmx.OpenTypeSupport.OpenTypeFactory; 045import org.apache.activemq.broker.region.AbstractRegion; 046import org.apache.activemq.broker.region.Destination; 047import org.apache.activemq.broker.region.DestinationFactory; 048import org.apache.activemq.broker.region.DestinationInterceptor; 049import org.apache.activemq.broker.region.DurableTopicSubscription; 050import org.apache.activemq.broker.region.MessageReference; 051import org.apache.activemq.broker.region.NullMessageReference; 052import org.apache.activemq.broker.region.Queue; 053import org.apache.activemq.broker.region.Region; 054import org.apache.activemq.broker.region.RegionBroker; 055import org.apache.activemq.broker.region.Subscription; 056import org.apache.activemq.broker.region.Topic; 057import org.apache.activemq.broker.region.TopicRegion; 058import org.apache.activemq.broker.region.TopicSubscription; 059import org.apache.activemq.broker.region.policy.AbortSlowAckConsumerStrategy; 060import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy; 061import org.apache.activemq.command.ActiveMQDestination; 062import org.apache.activemq.command.ActiveMQMessage; 063import org.apache.activemq.command.ActiveMQTopic; 064import org.apache.activemq.command.ConnectionInfo; 065import org.apache.activemq.command.ConsumerId; 066import org.apache.activemq.command.ConsumerInfo; 067import org.apache.activemq.command.Message; 068import org.apache.activemq.command.MessageAck; 069import org.apache.activemq.command.MessageId; 070import org.apache.activemq.command.ProducerInfo; 071import org.apache.activemq.command.SubscriptionInfo; 072import org.apache.activemq.thread.Scheduler; 073import org.apache.activemq.thread.TaskRunnerFactory; 074import org.apache.activemq.transaction.XATransaction; 075import org.apache.activemq.usage.SystemUsage; 076import org.apache.activemq.util.ServiceStopper; 077import org.apache.activemq.util.SubscriptionKey; 078import org.slf4j.Logger; 079import org.slf4j.LoggerFactory; 080 081public class ManagedRegionBroker extends RegionBroker { 082 private static final Logger LOG = LoggerFactory.getLogger(ManagedRegionBroker.class); 083 private final ManagementContext managementContext; 084 private final ObjectName brokerObjectName; 085 private final Map<ObjectName, DestinationView> topics = new ConcurrentHashMap<>(); 086 private final Map<ObjectName, DestinationView> queues = new ConcurrentHashMap<>(); 087 private final Map<ObjectName, DestinationView> temporaryQueues = new ConcurrentHashMap<>(); 088 private final Map<ObjectName, DestinationView> temporaryTopics = new ConcurrentHashMap<>(); 089 private final Map<ObjectName, SubscriptionView> queueSubscribers = new ConcurrentHashMap<>(); 090 private final Map<ObjectName, SubscriptionView> topicSubscribers = new ConcurrentHashMap<>(); 091 private final Map<ObjectName, SubscriptionView> durableTopicSubscribers = new ConcurrentHashMap<>(); 092 private final Map<ObjectName, SubscriptionView> inactiveDurableTopicSubscribers = new ConcurrentHashMap<>(); 093 private final Map<ObjectName, SubscriptionView> temporaryQueueSubscribers = new ConcurrentHashMap<>(); 094 private final Map<ObjectName, SubscriptionView> temporaryTopicSubscribers = new ConcurrentHashMap<>(); 095 private final Map<ObjectName, ProducerView> queueProducers = new ConcurrentHashMap<>(); 096 private final Map<ObjectName, ProducerView> topicProducers = new ConcurrentHashMap<>(); 097 private final Map<ObjectName, ProducerView> temporaryQueueProducers = new ConcurrentHashMap<>(); 098 private final Map<ObjectName, ProducerView> temporaryTopicProducers = new ConcurrentHashMap<>(); 099 private final Map<ObjectName, ProducerView> dynamicDestinationProducers = new ConcurrentHashMap<>(); 100 private final Map<SubscriptionKey, ObjectName> subscriptionKeys = new ConcurrentHashMap<>(); 101 private final Map<Subscription, ObjectName> subscriptionMap = new ConcurrentHashMap<>(); 102 private final Set<ObjectName> registeredMBeans = ConcurrentHashMap.newKeySet(); 103 /* This is the first broker in the broker interceptor chain. */ 104 private Broker contextBroker; 105 106 private final ExecutorService asyncInvokeService; 107 private final long mbeanTimeout; 108 109 public ManagedRegionBroker(BrokerService brokerService, ManagementContext context, ObjectName brokerObjectName, TaskRunnerFactory taskRunnerFactory, SystemUsage memoryManager, 110 DestinationFactory destinationFactory, DestinationInterceptor destinationInterceptor,Scheduler scheduler,ThreadPoolExecutor executor) throws IOException { 111 super(brokerService, taskRunnerFactory, memoryManager, destinationFactory, destinationInterceptor,scheduler,executor); 112 this.managementContext = context; 113 this.brokerObjectName = brokerObjectName; 114 this.mbeanTimeout = brokerService.getMbeanInvocationTimeout(); 115 this.asyncInvokeService = mbeanTimeout > 0 ? executor : null;; 116 } 117 118 @Override 119 public void start() throws Exception { 120 super.start(); 121 // build all existing durable subscriptions 122 buildExistingSubscriptions(); 123 } 124 125 @Override 126 protected void doStop(ServiceStopper stopper) { 127 super.doStop(stopper); 128 // lets remove any mbeans not yet removed 129 for (Iterator<ObjectName> iter = registeredMBeans.iterator(); iter.hasNext();) { 130 ObjectName name = iter.next(); 131 try { 132 managementContext.unregisterMBean(name); 133 } catch (InstanceNotFoundException e) { 134 LOG.warn("The MBean {} is no longer registered with JMX", name); 135 } catch (Exception e) { 136 stopper.onException(this, e); 137 } 138 } 139 registeredMBeans.clear(); 140 } 141 142 @Override 143 protected Region createQueueRegion(SystemUsage memoryManager, TaskRunnerFactory taskRunnerFactory, DestinationFactory destinationFactory) { 144 return new ManagedQueueRegion(this, destinationStatistics, memoryManager, taskRunnerFactory, destinationFactory); 145 } 146 147 @Override 148 protected Region createTempQueueRegion(SystemUsage memoryManager, TaskRunnerFactory taskRunnerFactory, DestinationFactory destinationFactory) { 149 return new ManagedTempQueueRegion(this, destinationStatistics, memoryManager, taskRunnerFactory, destinationFactory); 150 } 151 152 @Override 153 protected Region createTempTopicRegion(SystemUsage memoryManager, TaskRunnerFactory taskRunnerFactory, DestinationFactory destinationFactory) { 154 return new ManagedTempTopicRegion(this, destinationStatistics, memoryManager, taskRunnerFactory, destinationFactory); 155 } 156 157 @Override 158 protected Region createTopicRegion(SystemUsage memoryManager, TaskRunnerFactory taskRunnerFactory, DestinationFactory destinationFactory) { 159 return new ManagedTopicRegion(this, destinationStatistics, memoryManager, taskRunnerFactory, destinationFactory); 160 } 161 162 public void register(ActiveMQDestination destName, Destination destination) { 163 // TODO refactor to allow views for custom destinations 164 try { 165 ObjectName objectName = BrokerMBeanSupport.createDestinationName(brokerObjectName, destName); 166 DestinationView view; 167 if (destination instanceof Queue) { 168 view = new QueueView(this, (Queue)destination); 169 } else if (destination instanceof Topic) { 170 view = new TopicView(this, (Topic)destination); 171 } else { 172 view = null; 173 LOG.warn("JMX View is not supported for custom destination {}", destination); 174 } 175 if (view != null) { 176 registerDestination(objectName, destName, view); 177 } 178 } catch (Exception e) { 179 LOG.error("Failed to register destination {}", destName, e); 180 } 181 } 182 183 public void unregister(ActiveMQDestination destName) { 184 try { 185 ObjectName objectName = BrokerMBeanSupport.createDestinationName(brokerObjectName, destName); 186 unregisterDestination(objectName); 187 } catch (Exception e) { 188 LOG.error("Failed to unregister {}", destName, e); 189 } 190 } 191 192 public ObjectName registerSubscription(ConnectionContext context, Subscription sub) { 193 String connectionClientId = context.getClientId(); 194 195 SubscriptionKey key = new SubscriptionKey(context.getClientId(), sub.getConsumerInfo().getSubscriptionName()); 196 try { 197 ObjectName objectName = BrokerMBeanSupport.createSubscriptionName(brokerObjectName, connectionClientId, sub.getConsumerInfo()); 198 SubscriptionView view; 199 if (sub.getConsumerInfo().getConsumerId().getConnectionId().equals("OFFLINE")) { 200 // add offline subscribers to inactive list 201 SubscriptionInfo info = new SubscriptionInfo(); 202 info.setClientId(context.getClientId()); 203 info.setSubscriptionName(sub.getConsumerInfo().getSubscriptionName()); 204 info.setDestination(sub.getConsumerInfo().getDestination()); 205 info.setSelector(sub.getSelector()); 206 addInactiveSubscription(key, info, sub); 207 } else { 208 String userName = brokerService.isPopulateUserNameInMBeans() ? context.getUserName() : null; 209 if (sub.getConsumerInfo().isDurable()) { 210 view = new DurableSubscriptionView(this, brokerService, context.getClientId(), userName, sub); 211 } else { 212 if (sub instanceof TopicSubscription) { 213 view = new TopicSubscriptionView(context.getClientId(), userName, (TopicSubscription) sub); 214 } else { 215 view = new SubscriptionView(context.getClientId(), userName, sub); 216 } 217 } 218 registerSubscription(objectName, sub.getConsumerInfo(), key, view); 219 } 220 subscriptionMap.put(sub, objectName); 221 return objectName; 222 } catch (Exception e) { 223 LOG.error("Failed to register subscription {}", sub, e); 224 return null; 225 } 226 } 227 228 @Override 229 public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 230 super.addConnection(context, info); 231 this.contextBroker.getBrokerService().incrementCurrentConnections(); 232 this.contextBroker.getBrokerService().incrementTotalConnections(); 233 } 234 235 @Override 236 public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception { 237 super.removeConnection(context, info, error); 238 this.contextBroker.getBrokerService().decrementCurrentConnections(); 239 } 240 241 @Override 242 public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 243 Subscription sub = super.addConsumer(context, info); 244 SubscriptionKey subscriptionKey = new SubscriptionKey(sub.getContext().getClientId(), sub.getConsumerInfo().getSubscriptionName()); 245 ObjectName inactiveName = subscriptionKeys.get(subscriptionKey); 246 if (inactiveName != null) { 247 // if it was inactive, register it 248 registerSubscription(context, sub); 249 } 250 return sub; 251 } 252 253 @Override 254 public void removeConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 255 //Find subscriptions quickly by relying on the maps contained in the different Regions 256 //that map consumer ids and subscriptions 257 final Set<Subscription> subscriptions = findSubscriptions(info); 258 259 if (!subscriptions.isEmpty()) { 260 for (Subscription sub : subscriptions) { 261 // unregister all consumer subs 262 unregisterSubscription(subscriptionMap.get(sub), true); 263 break; 264 } 265 } else { 266 //Fall back to old slow approach where we go through the entire subscription map case something went wrong 267 //and no subscriptions were found - should generally not happen 268 for (Subscription sub : subscriptionMap.keySet()) { 269 if (sub.getConsumerInfo().equals(info)) { 270 unregisterSubscription(subscriptionMap.get(sub), true); 271 } 272 } 273 } 274 275 super.removeConsumer(context, info); 276 } 277 278 private Set<Subscription> findSubscriptions(final ConsumerInfo info) { 279 final Set<Subscription> subscriptions = new HashSet<>(); 280 281 try { 282 if (info.getDestination() != null) { 283 final ActiveMQDestination consumerDest = info.getDestination(); 284 //If it's composite then go through and find the subscription for every dest in case different 285 if (consumerDest.isComposite()) { 286 ActiveMQDestination[] destinations = consumerDest.getCompositeDestinations(); 287 for (ActiveMQDestination destination : destinations) { 288 addSubscriptionToList(subscriptions, info.getConsumerId(), destination); 289 } 290 } else { 291 //This is the case for a non-composite destination which would be most of the time 292 addSubscriptionToList(subscriptions, info.getConsumerId(), info.getDestination()); 293 } 294 } 295 } catch (Exception e) { 296 LOG.warn("Error finding subscription {}: {}", info, e.getMessage()); 297 } 298 299 return subscriptions; 300 } 301 302 private void addSubscriptionToList(Set<Subscription> subscriptions, 303 ConsumerId consumerId, ActiveMQDestination dest) throws JMSException { 304 final Subscription matchingSub = ((AbstractRegion) this.getRegion(dest)) 305 .getSubscriptions().get(consumerId); 306 if (matchingSub != null) { 307 subscriptions.add(matchingSub); 308 } 309 } 310 311 @Override 312 public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { 313 super.addProducer(context, info); 314 String connectionClientId = context.getClientId(); 315 ObjectName objectName = BrokerMBeanSupport.createProducerName(brokerObjectName, context.getClientId(), info); 316 String userName = brokerService.isPopulateUserNameInMBeans() ? context.getUserName() : null; 317 ProducerView view = new ProducerView(info, connectionClientId, userName, this); 318 registerProducer(objectName, info.getDestination(), view); 319 } 320 321 @Override 322 public void removeProducer(ConnectionContext context, ProducerInfo info) throws Exception { 323 ObjectName objectName = BrokerMBeanSupport.createProducerName(brokerObjectName, context.getClientId(), info); 324 unregisterProducer(objectName); 325 super.removeProducer(context, info); 326 } 327 328 @Override 329 public void send(ProducerBrokerExchange exchange, Message message) throws Exception { 330 if (exchange != null && exchange.getProducerState() != null && exchange.getProducerState().getInfo() != null) { 331 ProducerInfo info = exchange.getProducerState().getInfo(); 332 if (info.getDestination() == null && info.getProducerId() != null) { 333 ObjectName objectName = BrokerMBeanSupport.createProducerName(brokerObjectName, exchange.getConnectionContext().getClientId(), info); 334 ProducerView view = this.dynamicDestinationProducers.get(objectName); 335 if (view != null) { 336 ActiveMQDestination dest = message.getDestination(); 337 if (dest != null) { 338 view.setLastUsedDestinationName(dest); 339 } 340 } 341 } 342 } 343 super.send(exchange, message); 344 } 345 346 public void unregisterSubscription(Subscription sub) { 347 ObjectName name = subscriptionMap.remove(sub); 348 if (name != null) { 349 try { 350 SubscriptionKey subscriptionKey = new SubscriptionKey(sub.getContext().getClientId(), sub.getConsumerInfo().getSubscriptionName()); 351 ObjectName inactiveName = subscriptionKeys.remove(subscriptionKey); 352 if (inactiveName != null) { 353 inactiveDurableTopicSubscribers.remove(inactiveName); 354 managementContext.unregisterMBean(inactiveName); 355 } 356 } catch (Exception e) { 357 LOG.error("Failed to unregister subscription {}", sub, e); 358 } 359 } 360 } 361 362 protected void registerDestination(ObjectName key, ActiveMQDestination dest, DestinationView view) throws Exception { 363 if (dest.isQueue()) { 364 if (dest.isTemporary()) { 365 temporaryQueues.put(key, view); 366 } else { 367 queues.put(key, view); 368 } 369 } else { 370 if (dest.isTemporary()) { 371 temporaryTopics.put(key, view); 372 } else { 373 topics.put(key, view); 374 } 375 } 376 try { 377 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, key) != null) { 378 registeredMBeans.add(key); 379 } 380 } catch (Throwable e) { 381 LOG.warn("Failed to register MBean {}", key); 382 LOG.debug("Failure reason: ", e); 383 } 384 } 385 386 protected void unregisterDestination(ObjectName key) throws Exception { 387 388 DestinationView view = removeAndRemember(topics, key, null); 389 view = removeAndRemember(queues, key, view); 390 view = removeAndRemember(temporaryQueues, key, view); 391 view = removeAndRemember(temporaryTopics, key, view); 392 if (registeredMBeans.remove(key)) { 393 try { 394 managementContext.unregisterMBean(key); 395 } catch (Throwable e) { 396 LOG.warn("Failed to unregister MBean {}", key); 397 LOG.debug("Failure reason: ", e); 398 } 399 } 400 if (view != null) { 401 key = view.getSlowConsumerStrategy(); 402 if (key!= null && registeredMBeans.remove(key)) { 403 try { 404 managementContext.unregisterMBean(key); 405 } catch (Throwable e) { 406 LOG.warn("Failed to unregister slow consumer strategy MBean {}", key); 407 LOG.debug("Failure reason: ", e); 408 } 409 } 410 } 411 } 412 413 protected void registerProducer(ObjectName key, ActiveMQDestination dest, ProducerView view) throws Exception { 414 415 if (dest != null) { 416 if (dest.isQueue()) { 417 if (dest.isTemporary()) { 418 temporaryQueueProducers.put(key, view); 419 } else { 420 queueProducers.put(key, view); 421 } 422 } else { 423 if (dest.isTemporary()) { 424 temporaryTopicProducers.put(key, view); 425 } else { 426 topicProducers.put(key, view); 427 } 428 } 429 } else { 430 dynamicDestinationProducers.put(key, view); 431 } 432 433 try { 434 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, key) != null) { 435 registeredMBeans.add(key); 436 } 437 } catch (Throwable e) { 438 LOG.warn("Failed to register MBean {}", key); 439 LOG.debug("Failure reason: ", e); 440 } 441 } 442 443 protected void unregisterProducer(ObjectName key) throws Exception { 444 queueProducers.remove(key); 445 topicProducers.remove(key); 446 temporaryQueueProducers.remove(key); 447 temporaryTopicProducers.remove(key); 448 dynamicDestinationProducers.remove(key); 449 if (registeredMBeans.remove(key)) { 450 try { 451 managementContext.unregisterMBean(key); 452 } catch (Throwable e) { 453 LOG.warn("Failed to unregister MBean {}", key); 454 LOG.debug("Failure reason: ", e); 455 } 456 } 457 } 458 459 private DestinationView removeAndRemember(Map<ObjectName, DestinationView> map, ObjectName key, DestinationView view) { 460 DestinationView candidate = map.remove(key); 461 if (candidate != null && view == null) { 462 view = candidate; 463 } 464 return candidate != null ? candidate : view; 465 } 466 467 protected void registerSubscription(ObjectName key, ConsumerInfo info, SubscriptionKey subscriptionKey, SubscriptionView view) throws Exception { 468 ActiveMQDestination dest = info.getDestination(); 469 if (dest.isQueue()) { 470 if (dest.isTemporary()) { 471 temporaryQueueSubscribers.put(key, view); 472 } else { 473 queueSubscribers.put(key, view); 474 } 475 } else { 476 if (dest.isTemporary()) { 477 temporaryTopicSubscribers.put(key, view); 478 } else { 479 if (info.isDurable()) { 480 durableTopicSubscribers.put(key, view); 481 // unregister any inactive durable subs 482 try { 483 ObjectName inactiveName = subscriptionKeys.get(subscriptionKey); 484 if (inactiveName != null) { 485 inactiveDurableTopicSubscribers.remove(inactiveName); 486 registeredMBeans.remove(inactiveName); 487 managementContext.unregisterMBean(inactiveName); 488 } 489 } catch (Throwable e) { 490 LOG.error("Unable to unregister inactive durable subscriber {}", subscriptionKey, e); 491 } 492 } else { 493 topicSubscribers.put(key, view); 494 } 495 } 496 } 497 498 try { 499 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, key) != null) { 500 registeredMBeans.add(key); 501 } 502 } catch (Throwable e) { 503 LOG.warn("Failed to register MBean {}", key); 504 LOG.debug("Failure reason: ", e); 505 } 506 } 507 508 protected void unregisterSubscription(ObjectName key, boolean addToInactive) throws Exception { 509 queueSubscribers.remove(key); 510 topicSubscribers.remove(key); 511 temporaryQueueSubscribers.remove(key); 512 temporaryTopicSubscribers.remove(key); 513 if (registeredMBeans.remove(key)) { 514 try { 515 managementContext.unregisterMBean(key); 516 } catch (Throwable e) { 517 LOG.warn("Failed to unregister MBean {}", key); 518 LOG.debug("Failure reason: ", e); 519 } 520 } 521 DurableSubscriptionView view = (DurableSubscriptionView)durableTopicSubscribers.remove(key); 522 if (view != null) { 523 // need to put this back in the inactive list 524 SubscriptionKey subscriptionKey = new SubscriptionKey(view.getClientId(), view.getSubscriptionName()); 525 if (addToInactive) { 526 SubscriptionInfo info = new SubscriptionInfo(); 527 info.setClientId(subscriptionKey.getClientId()); 528 info.setSubscriptionName(subscriptionKey.getSubscriptionName()); 529 info.setDestination(new ActiveMQTopic(view.getDestinationName())); 530 info.setSelector(view.getSelector()); 531 addInactiveSubscription(subscriptionKey, info, (brokerService.isKeepDurableSubsActive() ? view.subscription : null)); 532 } 533 } 534 } 535 536 protected void buildExistingSubscriptions() throws Exception { 537 Map<SubscriptionKey, SubscriptionInfo> subscriptions = new HashMap<>(); 538 Set<ActiveMQDestination> destinations = destinationFactory.getDestinations(); 539 if (destinations != null) { 540 for (ActiveMQDestination dest : destinations) { 541 if (dest.isTopic()) { 542 SubscriptionInfo[] infos = destinationFactory.getAllDurableSubscriptions((ActiveMQTopic)dest); 543 if (infos != null) { 544 for (int i = 0; i < infos.length; i++) { 545 SubscriptionInfo info = infos[i]; 546 SubscriptionKey key = new SubscriptionKey(info); 547 if (!alreadyKnown(key)) { 548 LOG.debug("Restoring durable subscription MBean {}", info); 549 subscriptions.put(key, info); 550 } 551 } 552 } 553 } 554 } 555 } 556 557 for (Map.Entry<SubscriptionKey, SubscriptionInfo> entry : subscriptions.entrySet()) { 558 addInactiveSubscription(entry.getKey(), entry.getValue(), null); 559 } 560 } 561 562 private boolean alreadyKnown(SubscriptionKey key) { 563 boolean known = false; 564 known = ((TopicRegion) getTopicRegion()).durableSubscriptionExists(key); 565 LOG.trace("Sub with key: {}, {} already registered", key, (known ? "": "not")); 566 return known; 567 } 568 569 protected void addInactiveSubscription(SubscriptionKey key, SubscriptionInfo info, Subscription subscription) { 570 try { 571 ConsumerInfo offlineConsumerInfo = subscription != null ? subscription.getConsumerInfo() : ((TopicRegion)getTopicRegion()).createInactiveConsumerInfo(info); 572 ObjectName objectName = BrokerMBeanSupport.createSubscriptionName(brokerObjectName, info.getClientId(), offlineConsumerInfo); 573 SubscriptionView view = new InactiveDurableSubscriptionView(this, brokerService, key.getClientId(), info, subscription); 574 575 try { 576 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, objectName) != null) { 577 registeredMBeans.add(objectName); 578 } 579 } catch (Throwable e) { 580 LOG.warn("Failed to register MBean {}", key); 581 LOG.debug("Failure reason: ", e); 582 } 583 584 inactiveDurableTopicSubscribers.put(objectName, view); 585 subscriptionKeys.put(key, objectName); 586 } catch (Exception e) { 587 LOG.error("Failed to register subscription {}", info, e); 588 } 589 } 590 591 public CompositeData[] browse(SubscriptionView view) throws OpenDataException { 592 Message[] messages = getSubscriberMessages(view); 593 CompositeData c[] = new CompositeData[messages.length]; 594 for (int i = 0; i < c.length; i++) { 595 try { 596 c[i] = OpenTypeSupport.convert(messages[i]); 597 } catch (Throwable e) { 598 LOG.error("Failed to browse: {}", view, e); 599 } 600 } 601 return c; 602 } 603 604 public TabularData browseAsTable(SubscriptionView view) throws OpenDataException { 605 OpenTypeFactory factory = OpenTypeSupport.getFactory(ActiveMQMessage.class); 606 Message[] messages = getSubscriberMessages(view); 607 CompositeType ct = factory.getCompositeType(); 608 TabularType tt = new TabularType("MessageList", "MessageList", ct, new String[] {"JMSMessageID"}); 609 TabularDataSupport rc = new TabularDataSupport(tt); 610 for (int i = 0; i < messages.length; i++) { 611 rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i]))); 612 } 613 return rc; 614 } 615 616 public void remove(SubscriptionView view, String messageId) throws Exception { 617 ActiveMQDestination destination = getTopicDestination(view); 618 if (destination != null) { 619 final Destination topic = getTopicRegion().getDestinationMap().get(destination); 620 final MessageAck messageAck = new MessageAck(); 621 messageAck.setMessageID(new MessageId(messageId)); 622 messageAck.setDestination(destination); 623 624 topic.getMessageStore().removeMessage(brokerService.getAdminConnectionContext(), messageAck); 625 626 // if sub is active, remove from cursor 627 if (view.subscription instanceof DurableTopicSubscription) { 628 final DurableTopicSubscription durableTopicSubscription = (DurableTopicSubscription) view.subscription; 629 final MessageReference messageReference = new NullMessageReference(); 630 messageReference.getMessage().setMessageId(messageAck.getFirstMessageId()); 631 durableTopicSubscription.getPending().remove(messageReference); 632 } 633 634 } else { 635 throw new IllegalStateException("can't determine topic for sub:" + view); 636 } 637 } 638 639 protected Message[] getSubscriberMessages(SubscriptionView view) { 640 ActiveMQDestination destination = getTopicDestination(view); 641 if (destination != null) { 642 Destination topic = getTopicRegion().getDestinationMap().get(destination); 643 return topic.browse(); 644 645 } else { 646 LOG.warn("can't determine topic to browse for sub:" + view); 647 return new Message[]{}; 648 } 649 } 650 651 private ActiveMQDestination getTopicDestination(SubscriptionView view) { 652 ActiveMQDestination destination = null; 653 if (view.subscription instanceof DurableTopicSubscription) { 654 destination = new ActiveMQTopic(view.getDestinationName()); 655 } else if (view instanceof InactiveDurableSubscriptionView) { 656 destination = ((InactiveDurableSubscriptionView)view).subscriptionInfo.getDestination(); 657 } 658 return destination; 659 } 660 661 private ObjectName[] onlyNonSuppressed (Set<ObjectName> set){ 662 List<ObjectName> nonSuppressed = new ArrayList<>(); 663 for(ObjectName key : set){ 664 if (managementContext.isAllowedToRegister(key)){ 665 nonSuppressed.add(key); 666 } 667 } 668 return nonSuppressed.toArray(new ObjectName[nonSuppressed.size()]); 669 } 670 671 protected ObjectName[] getTopics() { 672 Set<ObjectName> set = topics.keySet(); 673 return set.toArray(new ObjectName[set.size()]); 674 } 675 676 protected ObjectName[] getTopicsNonSuppressed() { 677 return onlyNonSuppressed(topics.keySet()); 678 } 679 680 protected ObjectName[] getQueues() { 681 Set<ObjectName> set = queues.keySet(); 682 return set.toArray(new ObjectName[set.size()]); 683 } 684 685 protected ObjectName[] getQueuesNonSuppressed() { 686 return onlyNonSuppressed(queues.keySet()); 687 } 688 689 protected ObjectName[] getTemporaryTopics() { 690 Set<ObjectName> set = temporaryTopics.keySet(); 691 return set.toArray(new ObjectName[set.size()]); 692 } 693 694 protected ObjectName[] getTemporaryTopicsNonSuppressed() { 695 return onlyNonSuppressed(temporaryTopics.keySet()); 696 } 697 698 protected ObjectName[] getTemporaryQueues() { 699 Set<ObjectName> set = temporaryQueues.keySet(); 700 return set.toArray(new ObjectName[set.size()]); 701 } 702 703 protected ObjectName[] getTemporaryQueuesNonSuppressed() { 704 return onlyNonSuppressed(temporaryQueues.keySet()); 705 } 706 707 protected ObjectName[] getTopicSubscribers() { 708 Set<ObjectName> set = topicSubscribers.keySet(); 709 return set.toArray(new ObjectName[set.size()]); 710 } 711 712 protected ObjectName[] getTopicSubscribersNonSuppressed() { 713 return onlyNonSuppressed(topicSubscribers.keySet()); 714 } 715 716 protected ObjectName[] getDurableTopicSubscribers() { 717 Set<ObjectName> set = durableTopicSubscribers.keySet(); 718 return set.toArray(new ObjectName[set.size()]); 719 } 720 721 protected ObjectName[] getDurableTopicSubscribersNonSuppressed() { 722 return onlyNonSuppressed(durableTopicSubscribers.keySet()); 723 } 724 725 protected ObjectName[] getQueueSubscribers() { 726 Set<ObjectName> set = queueSubscribers.keySet(); 727 return set.toArray(new ObjectName[set.size()]); 728 } 729 730 protected ObjectName[] getQueueSubscribersNonSuppressed() { 731 return onlyNonSuppressed(queueSubscribers.keySet()); 732 } 733 734 protected ObjectName[] getTemporaryTopicSubscribers() { 735 Set<ObjectName> set = temporaryTopicSubscribers.keySet(); 736 return set.toArray(new ObjectName[set.size()]); 737 } 738 739 protected ObjectName[] getTemporaryTopicSubscribersNonSuppressed() { 740 return onlyNonSuppressed(temporaryTopicSubscribers.keySet()); 741 } 742 743 protected ObjectName[] getTemporaryQueueSubscribers() { 744 Set<ObjectName> set = temporaryQueueSubscribers.keySet(); 745 return set.toArray(new ObjectName[set.size()]); 746 } 747 748 protected ObjectName[] getTemporaryQueueSubscribersNonSuppressed() { 749 return onlyNonSuppressed(temporaryQueueSubscribers.keySet()); 750 } 751 752 protected ObjectName[] getInactiveDurableTopicSubscribers() { 753 Set<ObjectName> set = inactiveDurableTopicSubscribers.keySet(); 754 return set.toArray(new ObjectName[set.size()]); 755 } 756 757 protected ObjectName[] getInactiveDurableTopicSubscribersNonSuppressed() { 758 return onlyNonSuppressed(inactiveDurableTopicSubscribers.keySet()); 759 } 760 761 protected ObjectName[] getTopicProducers() { 762 Set<ObjectName> set = topicProducers.keySet(); 763 return set.toArray(new ObjectName[set.size()]); 764 } 765 766 protected ObjectName[] getTopicProducersNonSuppressed() { 767 return onlyNonSuppressed(topicProducers.keySet()); 768 } 769 770 protected ObjectName[] getQueueProducers() { 771 Set<ObjectName> set = queueProducers.keySet(); 772 return set.toArray(new ObjectName[set.size()]); 773 } 774 775 protected ObjectName[] getQueueProducersNonSuppressed() { 776 return onlyNonSuppressed(queueProducers.keySet()); 777 } 778 779 protected ObjectName[] getTemporaryTopicProducers() { 780 Set<ObjectName> set = temporaryTopicProducers.keySet(); 781 return set.toArray(new ObjectName[set.size()]); 782 } 783 784 protected ObjectName[] getTemporaryTopicProducersNonSuppressed() { 785 return onlyNonSuppressed(temporaryTopicProducers.keySet()); 786 } 787 788 protected ObjectName[] getTemporaryQueueProducers() { 789 Set<ObjectName> set = temporaryQueueProducers.keySet(); 790 return set.toArray(new ObjectName[set.size()]); 791 } 792 793 protected ObjectName[] getTemporaryQueueProducersNonSuppressed() { 794 return onlyNonSuppressed(temporaryQueueProducers.keySet()); 795 } 796 797 protected ObjectName[] getDynamicDestinationProducers() { 798 Set<ObjectName> set = dynamicDestinationProducers.keySet(); 799 return set.toArray(new ObjectName[set.size()]); 800 } 801 802 protected ObjectName[] getDynamicDestinationProducersNonSuppressed() { 803 return onlyNonSuppressed(dynamicDestinationProducers.keySet()); 804 } 805 806 public Broker getContextBroker() { 807 return contextBroker; 808 } 809 810 public void setContextBroker(Broker contextBroker) { 811 this.contextBroker = contextBroker; 812 } 813 814 public ObjectName registerSlowConsumerStrategy(AbortSlowConsumerStrategy strategy) throws MalformedObjectNameException { 815 ObjectName objectName = null; 816 try { 817 objectName = BrokerMBeanSupport.createAbortSlowConsumerStrategyName(brokerObjectName, strategy); 818 if (!registeredMBeans.contains(objectName)) { 819 820 AbortSlowConsumerStrategyView view = null; 821 if (strategy instanceof AbortSlowAckConsumerStrategy) { 822 view = new AbortSlowAckConsumerStrategyView(this, (AbortSlowAckConsumerStrategy) strategy); 823 } else { 824 view = new AbortSlowConsumerStrategyView(this, strategy); 825 } 826 827 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, objectName) != null) { 828 registeredMBeans.add(objectName); 829 } 830 } 831 } catch (Exception e) { 832 LOG.warn("Failed to register MBean {}", strategy); 833 LOG.debug("Failure reason: ", e); 834 } 835 return objectName; 836 } 837 838 public void registerRecoveredTransactionMBean(XATransaction transaction) { 839 try { 840 ObjectName objectName = BrokerMBeanSupport.createXATransactionName(brokerObjectName, transaction); 841 if (!registeredMBeans.contains(objectName)) { 842 RecoveredXATransactionView view = new RecoveredXATransactionView(this, transaction); 843 if (AsyncAnnotatedMBean.registerMBean(asyncInvokeService, mbeanTimeout, managementContext, view, objectName) != null) { 844 registeredMBeans.add(objectName); 845 } 846 } 847 } catch (Exception e) { 848 LOG.warn("Failed to register prepared transaction MBean {}", transaction); 849 LOG.debug("Failure reason: ", e); 850 } 851 } 852 853 public void unregister(XATransaction transaction) { 854 try { 855 ObjectName objectName = BrokerMBeanSupport.createXATransactionName(brokerObjectName, transaction); 856 if (registeredMBeans.remove(objectName)) { 857 try { 858 managementContext.unregisterMBean(objectName); 859 } catch (Throwable e) { 860 LOG.warn("Failed to unregister MBean {}", objectName); 861 LOG.debug("Failure reason: ", e); 862 } 863 } 864 } catch (Exception e) { 865 LOG.warn("Failed to create object name to unregister {}", transaction, e); 866 } 867 } 868 869 public ObjectName getSubscriberObjectName(Subscription key) { 870 return subscriptionMap.get(key); 871 } 872 873 public Subscription getSubscriber(ObjectName key) { 874 Subscription sub = null; 875 for (Entry<Subscription, ObjectName> entry: subscriptionMap.entrySet()) { 876 if (entry.getValue().equals(key)) { 877 sub = entry.getKey(); 878 break; 879 } 880 } 881 return sub; 882 } 883 884 public Map<ObjectName, DestinationView> getQueueViews() { 885 return queues; 886 } 887 888 public Map<ObjectName, DestinationView> getTopicViews() { 889 return topics; 890 } 891 892 public DestinationView getQueueView(String queueName) throws MalformedObjectNameException { 893 ObjectName objName = BrokerMBeanSupport.createDestinationName(brokerObjectName.toString(), "Queue", queueName); 894 return queues.get(objName); 895 } 896 897 public Set<ObjectName> getRegisteredMbeans() { 898 return registeredMBeans; 899 } 900}