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