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