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.net.URISyntaxException; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.Iterator; 025import java.util.List; 026import java.util.Map; 027import java.util.Map.Entry; 028 029import javax.jms.Connection; 030import javax.jms.InvalidSelectorException; 031import javax.jms.MessageProducer; 032import javax.jms.Session; 033import javax.management.MalformedObjectNameException; 034import javax.management.ObjectName; 035import javax.management.openmbean.CompositeData; 036import javax.management.openmbean.CompositeDataSupport; 037import javax.management.openmbean.CompositeType; 038import javax.management.openmbean.OpenDataException; 039import javax.management.openmbean.TabularData; 040import javax.management.openmbean.TabularDataSupport; 041import javax.management.openmbean.TabularType; 042 043import org.apache.activemq.ActiveMQConnectionFactory; 044import org.apache.activemq.broker.jmx.OpenTypeSupport.OpenTypeFactory; 045import org.apache.activemq.broker.region.Destination; 046import org.apache.activemq.broker.region.Subscription; 047import org.apache.activemq.broker.region.policy.AbortSlowConsumerStrategy; 048import org.apache.activemq.broker.region.policy.SlowConsumerStrategy; 049import org.apache.activemq.command.ActiveMQDestination; 050import org.apache.activemq.command.ActiveMQMessage; 051import org.apache.activemq.command.ActiveMQTextMessage; 052import org.apache.activemq.command.Message; 053import org.apache.activemq.filter.BooleanExpression; 054import org.apache.activemq.filter.NonCachedMessageEvaluationContext; 055import org.apache.activemq.selector.SelectorParser; 056import org.apache.activemq.store.MessageStore; 057import org.apache.activemq.util.URISupport; 058import org.slf4j.Logger; 059import org.slf4j.LoggerFactory; 060 061public class DestinationView implements DestinationViewMBean { 062 private static final Logger LOG = LoggerFactory.getLogger(DestinationViewMBean.class); 063 protected final Destination destination; 064 protected final ManagedRegionBroker broker; 065 066 public DestinationView(ManagedRegionBroker broker, Destination destination) { 067 this.broker = broker; 068 this.destination = destination; 069 } 070 071 public void gc() { 072 destination.gc(); 073 } 074 075 @Override 076 public String getName() { 077 return destination.getName(); 078 } 079 080 @Override 081 public void resetStatistics() { 082 destination.getDestinationStatistics().reset(); 083 } 084 085 @Override 086 public long getEnqueueCount() { 087 return destination.getDestinationStatistics().getEnqueues().getCount(); 088 } 089 090 @Override 091 public long getDequeueCount() { 092 return destination.getDestinationStatistics().getDequeues().getCount(); 093 } 094 095 @Override 096 public long getForwardCount() { 097 return destination.getDestinationStatistics().getForwards().getCount(); 098 } 099 100 @Override 101 public long getDispatchCount() { 102 return destination.getDestinationStatistics().getDispatched().getCount(); 103 } 104 105 @Override 106 public long getDuplicateFromStoreCount() { 107 return destination.getDestinationStatistics().getDuplicateFromStore().getCount(); 108 } 109 110 @Override 111 public long getInFlightCount() { 112 return destination.getDestinationStatistics().getInflight().getCount(); 113 } 114 115 @Override 116 public long getExpiredCount() { 117 return destination.getDestinationStatistics().getExpired().getCount(); 118 } 119 120 @Override 121 public long getConsumerCount() { 122 return destination.getDestinationStatistics().getConsumers().getCount(); 123 } 124 125 @Override 126 public long getQueueSize() { 127 return destination.getDestinationStatistics().getMessages().getCount(); 128 } 129 130 @Override 131 public long getStoreMessageSize() { 132 MessageStore messageStore = destination.getMessageStore(); 133 return messageStore != null ? messageStore.getMessageStoreStatistics().getMessageSize().getTotalSize() : 0; 134 } 135 136 public long getMessagesCached() { 137 return destination.getDestinationStatistics().getMessagesCached().getCount(); 138 } 139 140 @Override 141 public int getMemoryPercentUsage() { 142 return destination.getMemoryUsage().getPercentUsage(); 143 } 144 145 @Override 146 public long getMemoryUsageByteCount() { 147 return destination.getMemoryUsage().getUsage(); 148 } 149 150 @Override 151 public long getMemoryLimit() { 152 return destination.getMemoryUsage().getLimit(); 153 } 154 155 @Override 156 public void setMemoryLimit(long limit) { 157 destination.getMemoryUsage().setLimit(limit); 158 } 159 160 @Override 161 public double getAverageEnqueueTime() { 162 return destination.getDestinationStatistics().getProcessTime().getAverageTime(); 163 } 164 165 @Override 166 public int getTempUsagePercentUsage() { 167 return destination.getTempUsage().getPercentUsage(); 168 } 169 170 @Override 171 public long getTempUsageLimit() { 172 return destination.getTempUsage().getLimit(); 173 } 174 175 @Override 176 public void setTempUsageLimit(long limit) { 177 destination.getTempUsage().setLimit(limit); 178 } 179 180 @Override 181 public long getMaxEnqueueTime() { 182 return destination.getDestinationStatistics().getProcessTime().getMaxTime(); 183 } 184 185 @Override 186 public long getMinEnqueueTime() { 187 return destination.getDestinationStatistics().getProcessTime().getMinTime(); 188 } 189 190 /** 191 * @return the average size of a message (bytes) 192 */ 193 @Override 194 public long getAverageMessageSize() { 195 // we are okay with the size without decimals so cast to long 196 return (long) destination.getDestinationStatistics().getMessageSize().getAverageSize(); 197 } 198 199 /** 200 * @return the max size of a message (bytes) 201 */ 202 @Override 203 public long getMaxMessageSize() { 204 return destination.getDestinationStatistics().getMessageSize().getMaxSize(); 205 } 206 207 /** 208 * @return the min size of a message (bytes) 209 */ 210 @Override 211 public long getMinMessageSize() { 212 return destination.getDestinationStatistics().getMessageSize().getMinSize(); 213 } 214 215 216 @Override 217 public boolean isPrioritizedMessages() { 218 return destination.isPrioritizedMessages(); 219 } 220 221 @Override 222 public CompositeData[] browse() throws OpenDataException { 223 try { 224 return browse(null); 225 } catch (InvalidSelectorException e) { 226 // should not happen. 227 throw new RuntimeException(e); 228 } 229 } 230 231 @Override 232 public CompositeData[] browse(String selector) throws OpenDataException, InvalidSelectorException { 233 Message[] messages = destination.browse(); 234 ArrayList<CompositeData> c = new ArrayList<CompositeData>(); 235 236 NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext(); 237 ctx.setDestination(destination.getActiveMQDestination()); 238 BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector); 239 240 for (int i = 0; i < messages.length; i++) { 241 try { 242 243 if (selectorExpression == null) { 244 c.add(OpenTypeSupport.convert(messages[i])); 245 } else { 246 ctx.setMessageReference(messages[i]); 247 if (selectorExpression.matches(ctx)) { 248 c.add(OpenTypeSupport.convert(messages[i])); 249 } 250 } 251 252 } catch (Throwable e) { 253 LOG.warn("exception browsing destination", e); 254 } 255 } 256 257 CompositeData rc[] = new CompositeData[c.size()]; 258 c.toArray(rc); 259 return rc; 260 } 261 262 /** 263 * Browses the current destination returning a list of messages 264 */ 265 @Override 266 public List<Object> browseMessages() throws InvalidSelectorException { 267 return browseMessages(null); 268 } 269 270 /** 271 * Browses the current destination with the given selector returning a list 272 * of messages 273 */ 274 @Override 275 public List<Object> browseMessages(String selector) throws InvalidSelectorException { 276 Message[] messages = destination.browse(); 277 ArrayList<Object> answer = new ArrayList<Object>(); 278 279 NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext(); 280 ctx.setDestination(destination.getActiveMQDestination()); 281 BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector); 282 283 for (int i = 0; i < messages.length; i++) { 284 try { 285 Message message = messages[i]; 286 message.setReadOnlyBody(true); 287 if (selectorExpression == null) { 288 answer.add(message); 289 } else { 290 ctx.setMessageReference(message); 291 if (selectorExpression.matches(ctx)) { 292 answer.add(message); 293 } 294 } 295 296 } catch (Throwable e) { 297 LOG.warn("exception browsing destination", e); 298 } 299 } 300 return answer; 301 } 302 303 @Override 304 public TabularData browseAsTable() throws OpenDataException { 305 try { 306 return browseAsTable(null); 307 } catch (InvalidSelectorException e) { 308 throw new RuntimeException(e); 309 } 310 } 311 312 @Override 313 public TabularData browseAsTable(String selector) throws OpenDataException, InvalidSelectorException { 314 OpenTypeFactory factory = OpenTypeSupport.getFactory(ActiveMQMessage.class); 315 Message[] messages = destination.browse(); 316 CompositeType ct = factory.getCompositeType(); 317 TabularType tt = new TabularType("MessageList", "MessageList", ct, new String[] { "JMSMessageID" }); 318 TabularDataSupport rc = new TabularDataSupport(tt); 319 320 NonCachedMessageEvaluationContext ctx = new NonCachedMessageEvaluationContext(); 321 ctx.setDestination(destination.getActiveMQDestination()); 322 BooleanExpression selectorExpression = selector == null ? null : SelectorParser.parse(selector); 323 324 for (int i = 0; i < messages.length; i++) { 325 try { 326 if (selectorExpression == null) { 327 rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i]))); 328 } else { 329 ctx.setMessageReference(messages[i]); 330 if (selectorExpression.matches(ctx)) { 331 rc.put(new CompositeDataSupport(ct, factory.getFields(messages[i]))); 332 } 333 } 334 } catch (Throwable e) { 335 LOG.warn("exception browsing destination", e); 336 } 337 } 338 339 return rc; 340 } 341 342 @Override 343 public String sendTextMessageWithProperties(String properties) throws Exception { 344 Map<String, String> props = parseProps(properties, ","); 345 return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password")); 346 } 347 348 @Override 349 public String sendTextMessageWithProperties(String properties, String delimiter) throws Exception { 350 if (delimiter == null || delimiter.isEmpty()) { 351 return sendTextMessageWithProperties(properties); 352 } else { 353 Map<String, String> props = parseProps(properties, delimiter); 354 return sendTextMessage(props, props.remove("body"), props.remove("username"), props.remove("password")); 355 } 356 } 357 358 private Map<String, String> parseProps(String properties, String delimiter) { 359 String[] kvs = properties.split(delimiter); 360 Map<String, String> props = new HashMap<String, String>(); 361 for (String kv : kvs) { 362 String[] it = kv.split("="); 363 if (it.length == 2) { 364 props.put(it[0],it[1]); 365 } 366 } 367 return props; 368 } 369 370 @Override 371 public String sendTextMessage(String body) throws Exception { 372 return sendTextMessage(Collections.EMPTY_MAP, body); 373 } 374 375 @Override 376 public String sendTextMessage(Map headers, String body) throws Exception { 377 return sendTextMessage(headers, body, null, null); 378 } 379 380 @Override 381 public String sendTextMessage(String body, String user, @Sensitive String password) throws Exception { 382 return sendTextMessage(Collections.EMPTY_MAP, body, user, password); 383 } 384 385 @Override 386 public String sendTextMessage(Map<String, String> headers, String body, String userName, @Sensitive String password) throws Exception { 387 388 String brokerUrl = "vm://" + broker.getBrokerName(); 389 ActiveMQDestination dest = destination.getActiveMQDestination(); 390 391 ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(brokerUrl); 392 Connection connection = null; 393 try { 394 connection = cf.createConnection(userName, password); 395 Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); 396 MessageProducer producer = session.createProducer(dest); 397 ActiveMQTextMessage msg = (ActiveMQTextMessage) session.createTextMessage(body); 398 399 for (Iterator<Entry<String, String>> iter = headers.entrySet().iterator(); iter.hasNext();) { 400 Entry<String, String> entry = iter.next(); 401 msg.setObjectProperty(entry.getKey(), entry.getValue()); 402 } 403 404 producer.setDeliveryMode(msg.getJMSDeliveryMode()); 405 producer.setPriority(msg.getPriority()); 406 long ttl = 0; 407 if (msg.getExpiration() != 0) { 408 ttl = msg.getExpiration() - System.currentTimeMillis(); 409 } else { 410 String timeToLive = headers.get("timeToLive"); 411 if (timeToLive != null) { 412 ttl = Integer.valueOf(timeToLive); 413 } 414 } 415 producer.setTimeToLive(ttl > 0 ? ttl : 0); 416 producer.send(msg); 417 418 return msg.getJMSMessageID(); 419 420 } finally { 421 if (connection != null) { 422 connection.close(); 423 } 424 } 425 } 426 427 @Override 428 public int getMaxAuditDepth() { 429 return destination.getMaxAuditDepth(); 430 } 431 432 @Override 433 public int getMaxProducersToAudit() { 434 return destination.getMaxProducersToAudit(); 435 } 436 437 public boolean isEnableAudit() { 438 return destination.isEnableAudit(); 439 } 440 441 public void setEnableAudit(boolean enableAudit) { 442 destination.setEnableAudit(enableAudit); 443 } 444 445 @Override 446 public void setMaxAuditDepth(int maxAuditDepth) { 447 destination.setMaxAuditDepth(maxAuditDepth); 448 } 449 450 @Override 451 public void setMaxProducersToAudit(int maxProducersToAudit) { 452 destination.setMaxProducersToAudit(maxProducersToAudit); 453 } 454 455 @Override 456 public float getMemoryUsagePortion() { 457 return destination.getMemoryUsage().getUsagePortion(); 458 } 459 460 @Override 461 public long getProducerCount() { 462 return destination.getDestinationStatistics().getProducers().getCount(); 463 } 464 465 @Override 466 public boolean isProducerFlowControl() { 467 return destination.isProducerFlowControl(); 468 } 469 470 @Override 471 public void setMemoryUsagePortion(float value) { 472 destination.getMemoryUsage().setUsagePortion(value); 473 } 474 475 @Override 476 public void setProducerFlowControl(boolean producerFlowControl) { 477 destination.setProducerFlowControl(producerFlowControl); 478 } 479 480 @Override 481 public boolean isAlwaysRetroactive() { 482 return destination.isAlwaysRetroactive(); 483 } 484 485 @Override 486 public void setAlwaysRetroactive(boolean alwaysRetroactive) { 487 destination.setAlwaysRetroactive(alwaysRetroactive); 488 } 489 490 /** 491 * Set's the interval at which warnings about producers being blocked by 492 * resource usage will be triggered. Values of 0 or less will disable 493 * warnings 494 * 495 * @param blockedProducerWarningInterval the interval at which warning about 496 * blocked producers will be triggered. 497 */ 498 @Override 499 public void setBlockedProducerWarningInterval(long blockedProducerWarningInterval) { 500 destination.setBlockedProducerWarningInterval(blockedProducerWarningInterval); 501 } 502 503 /** 504 * 505 * @return the interval at which warning about blocked producers will be 506 * triggered. 507 */ 508 @Override 509 public long getBlockedProducerWarningInterval() { 510 return destination.getBlockedProducerWarningInterval(); 511 } 512 513 @Override 514 public int getMaxPageSize() { 515 return destination.getMaxPageSize(); 516 } 517 518 @Override 519 public void setMaxPageSize(int pageSize) { 520 destination.setMaxPageSize(pageSize); 521 } 522 523 @Override 524 public boolean isUseCache() { 525 return destination.isUseCache(); 526 } 527 528 @Override 529 public void setUseCache(boolean value) { 530 destination.setUseCache(value); 531 } 532 533 @Override 534 public ObjectName[] getSubscriptions() throws IOException, MalformedObjectNameException { 535 List<Subscription> subscriptions = destination.getConsumers(); 536 ObjectName[] answer = new ObjectName[subscriptions.size()]; 537 ObjectName brokerObjectName = broker.getBrokerService().getBrokerObjectName(); 538 int index = 0; 539 for (Subscription subscription : subscriptions) { 540 String connectionClientId = subscription.getContext().getClientId(); 541 answer[index++] = BrokerMBeanSupport.createSubscriptionName(brokerObjectName, connectionClientId, subscription.getConsumerInfo()); 542 } 543 return answer; 544 } 545 546 @Override 547 public ObjectName getSlowConsumerStrategy() throws IOException, MalformedObjectNameException { 548 ObjectName result = null; 549 SlowConsumerStrategy strategy = destination.getSlowConsumerStrategy(); 550 if (strategy != null && strategy instanceof AbortSlowConsumerStrategy) { 551 result = broker.registerSlowConsumerStrategy((AbortSlowConsumerStrategy)strategy); 552 } 553 return result; 554 } 555 556 @Override 557 public String getOptions() { 558 Map<String, String> options = destination.getActiveMQDestination().getOptions(); 559 String optionsString = ""; 560 try { 561 if (options != null) { 562 optionsString = URISupport.createQueryString(options); 563 } 564 } catch (URISyntaxException ignored) {} 565 return optionsString; 566 } 567 568 @Override 569 public boolean isDLQ() { 570 return destination.getActiveMQDestination().isDLQ(); 571 } 572 573 @Override 574 public void setDLQ(boolean val) { 575 destination.getActiveMQDestination().setDLQ(val); 576 } 577 578 @Override 579 public long getBlockedSends() { 580 return destination.getDestinationStatistics().getBlockedSends().getCount(); 581 } 582 583 @Override 584 public double getAverageBlockedTime() { 585 return destination.getDestinationStatistics().getBlockedTime().getAverageTime(); 586 } 587 588 @Override 589 public long getTotalBlockedTime() { 590 return destination.getDestinationStatistics().getBlockedTime().getTotalTime(); 591 } 592 593 @Override 594 public boolean isSendDuplicateFromStoreToDLQ() { 595 return destination.isSendDuplicateFromStoreToDLQ(); 596 } 597}