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.camel.management.mbean; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.Comparator; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027import java.util.concurrent.RejectedExecutionException; 028import java.util.concurrent.TimeUnit; 029 030import javax.management.AttributeValueExp; 031import javax.management.MBeanServer; 032import javax.management.ObjectName; 033import javax.management.Query; 034import javax.management.QueryExp; 035import javax.management.StringValueExp; 036import javax.management.openmbean.CompositeData; 037import javax.management.openmbean.CompositeDataSupport; 038import javax.management.openmbean.CompositeType; 039import javax.management.openmbean.TabularData; 040import javax.management.openmbean.TabularDataSupport; 041 042import org.apache.camel.CamelContext; 043import org.apache.camel.ExtendedCamelContext; 044import org.apache.camel.ManagementStatisticsLevel; 045import org.apache.camel.Route; 046import org.apache.camel.RuntimeCamelException; 047import org.apache.camel.ServiceStatus; 048import org.apache.camel.TimerListener; 049import org.apache.camel.api.management.ManagedResource; 050import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes; 051import org.apache.camel.api.management.mbean.ManagedProcessorMBean; 052import org.apache.camel.api.management.mbean.ManagedRouteMBean; 053import org.apache.camel.api.management.mbean.ManagedStepMBean; 054import org.apache.camel.api.management.mbean.RouteError; 055import org.apache.camel.model.Model; 056import org.apache.camel.model.ModelCamelContext; 057import org.apache.camel.model.RouteDefinition; 058import org.apache.camel.spi.InflightRepository; 059import org.apache.camel.spi.ManagementStrategy; 060import org.apache.camel.spi.RoutePolicy; 061import org.apache.camel.util.ObjectHelper; 062import org.slf4j.Logger; 063import org.slf4j.LoggerFactory; 064 065@ManagedResource(description = "Managed Route") 066public class ManagedRoute extends ManagedPerformanceCounter implements TimerListener, ManagedRouteMBean { 067 068 public static final String VALUE_UNKNOWN = "Unknown"; 069 070 private static final Logger LOG = LoggerFactory.getLogger(ManagedRoute.class); 071 072 protected final Route route; 073 protected final String description; 074 protected final String configurationId; 075 protected final String sourceLocation; 076 protected final CamelContext context; 077 private final LoadTriplet load = new LoadTriplet(); 078 private final String jmxDomain; 079 080 public ManagedRoute(CamelContext context, Route route) { 081 this.route = route; 082 this.context = context; 083 this.description = route.getDescription(); 084 this.configurationId = route.getConfigurationId(); 085 this.sourceLocation = route.getSourceResource() != null ? route.getSourceResource().getLocation() : null; 086 this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName(); 087 } 088 089 @Override 090 public void init(ManagementStrategy strategy) { 091 super.init(strategy); 092 boolean enabled 093 = context.getManagementStrategy().getManagementAgent().getStatisticsLevel() != ManagementStatisticsLevel.Off; 094 setStatisticsEnabled(enabled); 095 } 096 097 public Route getRoute() { 098 return route; 099 } 100 101 public CamelContext getContext() { 102 return context; 103 } 104 105 @Override 106 public String getRouteId() { 107 String id = route.getId(); 108 if (id == null) { 109 id = VALUE_UNKNOWN; 110 } 111 return id; 112 } 113 114 @Override 115 public String getRouteGroup() { 116 return route.getGroup(); 117 } 118 119 @Override 120 public TabularData getRouteProperties() { 121 try { 122 final Map<String, Object> properties = route.getProperties(); 123 final TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.camelRoutePropertiesTabularType()); 124 final CompositeType ct = CamelOpenMBeanTypes.camelRoutePropertiesCompositeType(); 125 126 // gather route properties 127 for (Map.Entry<String, Object> entry : properties.entrySet()) { 128 final String key = entry.getKey(); 129 final String val = context.getTypeConverter().convertTo(String.class, entry.getValue()); 130 131 CompositeData data = new CompositeDataSupport( 132 ct, 133 new String[] { "key", "value" }, 134 new Object[] { key, val }); 135 136 answer.put(data); 137 } 138 return answer; 139 } catch (Exception e) { 140 throw RuntimeCamelException.wrapRuntimeCamelException(e); 141 } 142 } 143 144 @Override 145 public String getDescription() { 146 return description; 147 } 148 149 @Override 150 public String getSourceLocation() { 151 return sourceLocation; 152 } 153 154 @Override 155 public String getRouteConfigurationId() { 156 return configurationId; 157 } 158 159 @Override 160 public String getEndpointUri() { 161 if (route.getEndpoint() != null) { 162 return route.getEndpoint().getEndpointUri(); 163 } 164 return VALUE_UNKNOWN; 165 } 166 167 @Override 168 public String getState() { 169 // must use String type to be sure remote JMX can read the attribute without requiring Camel classes. 170 ServiceStatus status = context.getRouteController().getRouteStatus(route.getId()); 171 // if no status exists then its stopped 172 if (status == null) { 173 status = ServiceStatus.Stopped; 174 } 175 return status.name(); 176 } 177 178 @Override 179 public String getUptime() { 180 return route.getUptime(); 181 } 182 183 @Override 184 public long getUptimeMillis() { 185 return route.getUptimeMillis(); 186 } 187 188 @Override 189 public String getCamelId() { 190 return context.getName(); 191 } 192 193 @Override 194 public String getCamelManagementName() { 195 return context.getManagementName(); 196 } 197 198 @Override 199 public Boolean getTracing() { 200 return route.isTracing(); 201 } 202 203 @Override 204 public void setTracing(Boolean tracing) { 205 route.setTracing(tracing); 206 } 207 208 @Override 209 public Boolean getMessageHistory() { 210 return route.isMessageHistory(); 211 } 212 213 @Override 214 public Boolean getLogMask() { 215 return route.isLogMask(); 216 } 217 218 @Override 219 public String getRoutePolicyList() { 220 List<RoutePolicy> policyList = route.getRoutePolicyList(); 221 222 if (policyList == null || policyList.isEmpty()) { 223 // return an empty string to have it displayed nicely in JMX consoles 224 return ""; 225 } 226 227 StringBuilder sb = new StringBuilder(); 228 for (int i = 0; i < policyList.size(); i++) { 229 RoutePolicy policy = policyList.get(i); 230 sb.append(policy.getClass().getSimpleName()); 231 sb.append("(").append(ObjectHelper.getIdentityHashCode(policy)).append(")"); 232 if (i < policyList.size() - 1) { 233 sb.append(", "); 234 } 235 } 236 return sb.toString(); 237 } 238 239 @Override 240 public String getLoad01() { 241 double load1 = load.getLoad1(); 242 if (Double.isNaN(load1)) { 243 // empty string if load statistics is disabled 244 return ""; 245 } else { 246 return String.format("%.2f", load1); 247 } 248 } 249 250 @Override 251 public String getLoad05() { 252 double load5 = load.getLoad5(); 253 if (Double.isNaN(load5)) { 254 // empty string if load statistics is disabled 255 return ""; 256 } else { 257 return String.format("%.2f", load5); 258 } 259 } 260 261 @Override 262 public String getLoad15() { 263 double load15 = load.getLoad15(); 264 if (Double.isNaN(load15)) { 265 // empty string if load statistics is disabled 266 return ""; 267 } else { 268 return String.format("%.2f", load15); 269 } 270 } 271 272 @Override 273 public void onTimer() { 274 load.update(getInflightExchanges()); 275 } 276 277 @Override 278 public void start() throws Exception { 279 if (!context.getStatus().isStarted()) { 280 throw new IllegalArgumentException("CamelContext is not started"); 281 } 282 context.getRouteController().startRoute(getRouteId()); 283 } 284 285 @Override 286 public void stop() throws Exception { 287 if (!context.getStatus().isStarted()) { 288 throw new IllegalArgumentException("CamelContext is not started"); 289 } 290 context.getRouteController().stopRoute(getRouteId()); 291 } 292 293 @Override 294 public void stopAndFail() throws Exception { 295 if (!context.getStatus().isStarted()) { 296 throw new IllegalArgumentException("CamelContext is not started"); 297 } 298 Throwable cause = new RejectedExecutionException("Route " + getRouteId() + " is forced stopped and marked as failed"); 299 context.getRouteController().stopRoute(getRouteId(), cause); 300 } 301 302 @Override 303 public void stop(long timeout) throws Exception { 304 if (!context.getStatus().isStarted()) { 305 throw new IllegalArgumentException("CamelContext is not started"); 306 } 307 context.getRouteController().stopRoute(getRouteId(), timeout, TimeUnit.SECONDS); 308 } 309 310 @Override 311 public boolean stop(Long timeout, Boolean abortAfterTimeout) throws Exception { 312 if (!context.getStatus().isStarted()) { 313 throw new IllegalArgumentException("CamelContext is not started"); 314 } 315 return context.getRouteController().stopRoute(getRouteId(), timeout, TimeUnit.SECONDS, abortAfterTimeout); 316 } 317 318 public void shutdown() throws Exception { 319 if (!context.getStatus().isStarted()) { 320 throw new IllegalArgumentException("CamelContext is not started"); 321 } 322 String routeId = getRouteId(); 323 context.getRouteController().stopRoute(routeId); 324 context.removeRoute(routeId); 325 } 326 327 public void shutdown(long timeout) throws Exception { 328 if (!context.getStatus().isStarted()) { 329 throw new IllegalArgumentException("CamelContext is not started"); 330 } 331 String routeId = getRouteId(); 332 context.getRouteController().stopRoute(routeId, timeout, TimeUnit.SECONDS); 333 context.removeRoute(routeId); 334 } 335 336 @Override 337 public boolean remove() throws Exception { 338 if (!context.getStatus().isStarted()) { 339 throw new IllegalArgumentException("CamelContext is not started"); 340 } 341 return context.removeRoute(getRouteId()); 342 } 343 344 @Override 345 public void restart() throws Exception { 346 restart(1); 347 } 348 349 @Override 350 public void restart(long delay) throws Exception { 351 stop(); 352 if (delay > 0) { 353 try { 354 LOG.debug("Sleeping {} seconds before starting route: {}", delay, getRouteId()); 355 Thread.sleep(delay * 1000); 356 } catch (InterruptedException e) { 357 // ignore 358 } 359 } 360 start(); 361 } 362 363 @Override 364 public String dumpRouteAsXml() throws Exception { 365 return dumpRouteAsXml(false, false); 366 } 367 368 @Override 369 public String dumpRouteAsXml(boolean resolvePlaceholders) throws Exception { 370 return dumpRouteAsXml(resolvePlaceholders, false); 371 } 372 373 @Override 374 public String dumpRouteAsXml(boolean resolvePlaceholders, boolean resolveDelegateEndpoints) throws Exception { 375 String id = route.getId(); 376 RouteDefinition def = context.getExtension(Model.class).getRouteDefinition(id); 377 if (def != null) { 378 ExtendedCamelContext ecc = context.adapt(ExtendedCamelContext.class); 379 return ecc.getModelToXMLDumper().dumpModelAsXml(context, def, resolvePlaceholders, resolveDelegateEndpoints); 380 } 381 382 return null; 383 } 384 385 @Override 386 public String dumpRouteStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception { 387 // in this logic we need to calculate the accumulated processing time for the processor in the route 388 // and hence why the logic is a bit more complicated to do this, as we need to calculate that from 389 // the bottom -> top of the route but this information is valuable for profiling routes 390 StringBuilder sb = new StringBuilder(); 391 392 // need to calculate this value first, as we need that value for the route stat 393 long processorAccumulatedTime = 0L; 394 395 // gather all the processors for this route, which requires JMX 396 if (includeProcessors) { 397 sb.append(" <processorStats>\n"); 398 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 399 if (server != null) { 400 // get all the processor mbeans and sort them accordingly to their index 401 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 402 ObjectName query = ObjectName.getInstance( 403 jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*"); 404 Set<ObjectName> names = server.queryNames(query, null); 405 List<ManagedProcessorMBean> mps = new ArrayList<>(); 406 for (ObjectName on : names) { 407 ManagedProcessorMBean processor = context.getManagementStrategy().getManagementAgent().newProxyClient(on, 408 ManagedProcessorMBean.class); 409 410 // the processor must belong to this route 411 if (getRouteId().equals(processor.getRouteId())) { 412 mps.add(processor); 413 } 414 } 415 mps.sort(new OrderProcessorMBeans()); 416 417 // walk the processors in reverse order, and calculate the accumulated total time 418 Map<String, Long> accumulatedTimes = new HashMap<>(); 419 Collections.reverse(mps); 420 for (ManagedProcessorMBean processor : mps) { 421 processorAccumulatedTime += processor.getTotalProcessingTime(); 422 accumulatedTimes.put(processor.getProcessorId(), processorAccumulatedTime); 423 } 424 // and reverse back again 425 Collections.reverse(mps); 426 427 // and now add the sorted list of processors to the xml output 428 for (ManagedProcessorMBean processor : mps) { 429 int line = processor.getSourceLineNumber() != null ? processor.getSourceLineNumber() : -1; 430 sb.append(" <processorStat") 431 .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"", 432 processor.getProcessorId(), processor.getIndex(), processor.getState(), line)); 433 // do we have an accumulated time then append that 434 Long accTime = accumulatedTimes.get(processor.getProcessorId()); 435 if (accTime != null) { 436 sb.append(" accumulatedProcessingTime=\"").append(accTime).append("\""); 437 } 438 // use substring as we only want the attributes 439 sb.append(" ").append(processor.dumpStatsAsXml(fullStats).substring(7)).append("\n"); 440 } 441 } 442 sb.append(" </processorStats>\n"); 443 } 444 445 // route self time is route total - processor accumulated total) 446 long routeSelfTime = getTotalProcessingTime() - processorAccumulatedTime; 447 if (routeSelfTime < 0) { 448 // ensure we don't calculate that as negative 449 routeSelfTime = 0; 450 } 451 452 StringBuilder answer = new StringBuilder(); 453 answer.append("<routeStat").append(String.format(" id=\"%s\"", route.getId())) 454 .append(String.format(" state=\"%s\"", getState())); 455 if (sourceLocation != null) { 456 answer.append(String.format(" sourceLocation=\"%s\"", getSourceLocation())); 457 } 458 // use substring as we only want the attributes 459 String stat = dumpStatsAsXml(fullStats); 460 answer.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 461 answer.append(" selfProcessingTime=\"").append(routeSelfTime).append("\""); 462 InflightRepository.InflightExchange oldest = getOldestInflightEntry(); 463 if (oldest == null) { 464 answer.append(" oldestInflightExchangeId=\"\""); 465 answer.append(" oldestInflightDuration=\"\""); 466 } else { 467 answer.append(" oldestInflightExchangeId=\"").append(oldest.getExchange().getExchangeId()).append("\""); 468 answer.append(" oldestInflightDuration=\"").append(oldest.getDuration()).append("\""); 469 } 470 answer.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 471 472 if (includeProcessors) { 473 answer.append(sb); 474 } 475 476 answer.append("</routeStat>"); 477 return answer.toString(); 478 } 479 480 @Override 481 public String dumpStepStatsAsXml(boolean fullStats) throws Exception { 482 // in this logic we need to calculate the accumulated processing time for the processor in the route 483 // and hence why the logic is a bit more complicated to do this, as we need to calculate that from 484 // the bottom -> top of the route but this information is valuable for profiling routes 485 StringBuilder sb = new StringBuilder(); 486 487 // gather all the steps for this route, which requires JMX 488 sb.append(" <stepStats>\n"); 489 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 490 if (server != null) { 491 // get all the processor mbeans and sort them accordingly to their index 492 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 493 ObjectName query = ObjectName 494 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=steps,*"); 495 Set<ObjectName> names = server.queryNames(query, null); 496 List<ManagedStepMBean> mps = new ArrayList<>(); 497 for (ObjectName on : names) { 498 ManagedStepMBean step 499 = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedStepMBean.class); 500 501 // the step must belong to this route 502 if (getRouteId().equals(step.getRouteId())) { 503 mps.add(step); 504 } 505 } 506 mps.sort(new OrderProcessorMBeans()); 507 508 // and now add the sorted list of steps to the xml output 509 for (ManagedStepMBean step : mps) { 510 int line = step.getSourceLineNumber() != null ? step.getSourceLineNumber() : -1; 511 sb.append(" <stepStat") 512 .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"", 513 step.getProcessorId(), 514 step.getIndex(), step.getState(), line)); 515 // use substring as we only want the attributes 516 sb.append(" ").append(step.dumpStatsAsXml(fullStats).substring(7)).append("\n"); 517 } 518 } 519 sb.append(" </stepStats>\n"); 520 521 StringBuilder answer = new StringBuilder(); 522 answer.append("<routeStat").append(String.format(" id=\"%s\"", route.getId())) 523 .append(String.format(" state=\"%s\"", getState())); 524 if (sourceLocation != null) { 525 answer.append(String.format(" sourceLocation=\"%s\"", getSourceLocation())); 526 } 527 // use substring as we only want the attributes 528 String stat = dumpStatsAsXml(fullStats); 529 answer.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 530 InflightRepository.InflightExchange oldest = getOldestInflightEntry(); 531 if (oldest == null) { 532 answer.append(" oldestInflightExchangeId=\"\""); 533 answer.append(" oldestInflightDuration=\"\""); 534 } else { 535 answer.append(" oldestInflightExchangeId=\"").append(oldest.getExchange().getExchangeId()).append("\""); 536 answer.append(" oldestInflightDuration=\"").append(oldest.getDuration()).append("\""); 537 } 538 answer.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 539 540 answer.append(sb); 541 542 answer.append("</routeStat>"); 543 return answer.toString(); 544 } 545 546 @Override 547 public String dumpRouteSourceLocationsAsXml() throws Exception { 548 StringBuilder sb = new StringBuilder(); 549 sb.append("<routeLocations>"); 550 551 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 552 if (server != null) { 553 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 554 List<ManagedProcessorMBean> processors = new ArrayList<>(); 555 // gather all the processors for this CamelContext, which requires JMX 556 ObjectName query = ObjectName 557 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*"); 558 Set<ObjectName> names = server.queryNames(query, null); 559 for (ObjectName on : names) { 560 ManagedProcessorMBean processor 561 = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedProcessorMBean.class); 562 // the processor must belong to this route 563 if (getRouteId().equals(processor.getRouteId())) { 564 processors.add(processor); 565 } 566 } 567 processors.sort(new OrderProcessorMBeans()); 568 569 // grab route consumer 570 RouteDefinition rd = context.adapt(ModelCamelContext.class).getRouteDefinition(route.getRouteId()); 571 if (rd != null) { 572 String id = rd.getRouteId(); 573 int line = rd.getInput().getLineNumber(); 574 String location = getSourceLocation() != null ? getSourceLocation() : ""; 575 sb.append("\n <routeLocation") 576 .append(String.format( 577 " routeId=\"%s\" id=\"%s\" index=\"%s\" sourceLocation=\"%s\" sourceLineNumber=\"%s\"/>", 578 route.getRouteId(), id, 0, location, line)); 579 } 580 for (ManagedProcessorMBean processor : processors) { 581 // the step must belong to this route 582 if (route.getRouteId().equals(processor.getRouteId())) { 583 int line = processor.getSourceLineNumber() != null ? processor.getSourceLineNumber() : -1; 584 String location = processor.getSourceLocation() != null ? processor.getSourceLocation() : ""; 585 sb.append("\n <routeLocation") 586 .append(String.format( 587 " routeId=\"%s\" id=\"%s\" index=\"%s\" sourceLocation=\"%s\" sourceLineNumber=\"%s\"/>", 588 route.getRouteId(), processor.getProcessorId(), processor.getIndex(), location, line)); 589 } 590 } 591 } 592 sb.append("\n</routeLocations>"); 593 return sb.toString(); 594 } 595 596 @Override 597 public void reset(boolean includeProcessors) throws Exception { 598 reset(); 599 600 // and now reset all processors for this route 601 if (includeProcessors) { 602 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 603 if (server != null) { 604 // get all the processor mbeans and sort them accordingly to their index 605 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 606 ObjectName query = ObjectName.getInstance( 607 jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*"); 608 QueryExp queryExp = Query.match(new AttributeValueExp("RouteId"), new StringValueExp(getRouteId())); 609 Set<ObjectName> names = server.queryNames(query, queryExp); 610 for (ObjectName name : names) { 611 server.invoke(name, "reset", null, null); 612 } 613 } 614 } 615 } 616 617 @Override 618 public boolean equals(Object o) { 619 return this == o || o != null && getClass() == o.getClass() && route.equals(((ManagedRoute) o).route); 620 } 621 622 @Override 623 public int hashCode() { 624 return route.hashCode(); 625 } 626 627 private InflightRepository.InflightExchange getOldestInflightEntry() { 628 return getContext().getInflightRepository().oldest(getRouteId()); 629 } 630 631 @Override 632 public Long getOldestInflightDuration() { 633 InflightRepository.InflightExchange oldest = getOldestInflightEntry(); 634 if (oldest == null) { 635 return null; 636 } else { 637 return oldest.getDuration(); 638 } 639 } 640 641 @Override 642 public String getOldestInflightExchangeId() { 643 InflightRepository.InflightExchange oldest = getOldestInflightEntry(); 644 if (oldest == null) { 645 return null; 646 } else { 647 return oldest.getExchange().getExchangeId(); 648 } 649 } 650 651 @Override 652 public Boolean getHasRouteController() { 653 return route.getRouteController() != null; 654 } 655 656 @Override 657 public RouteError getLastError() { 658 org.apache.camel.spi.RouteError error = route.getLastError(); 659 if (error == null) { 660 return null; 661 } else { 662 return new RouteError() { 663 @Override 664 public Phase getPhase() { 665 if (error.getPhase() != null) { 666 switch (error.getPhase()) { 667 case START: 668 return Phase.START; 669 case STOP: 670 return Phase.STOP; 671 case SUSPEND: 672 return Phase.SUSPEND; 673 case RESUME: 674 return Phase.RESUME; 675 case SHUTDOWN: 676 return Phase.SHUTDOWN; 677 case REMOVE: 678 return Phase.REMOVE; 679 default: 680 throw new IllegalStateException(); 681 } 682 } 683 return null; 684 } 685 686 @Override 687 public Throwable getException() { 688 return error.getException(); 689 } 690 }; 691 } 692 } 693 694 private Integer getInflightExchanges() { 695 return (int) super.getExchangesInflight(); 696 } 697 698 /** 699 * Used for sorting the processor mbeans accordingly to their index. 700 */ 701 private static final class OrderProcessorMBeans implements Comparator<ManagedProcessorMBean>, Serializable { 702 703 @Override 704 public int compare(ManagedProcessorMBean o1, ManagedProcessorMBean o2) { 705 return o1.getIndex().compareTo(o2.getIndex()); 706 } 707 } 708}