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.ByteArrayInputStream; 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.Comparator; 023import java.util.List; 024import java.util.Map; 025import java.util.Set; 026import java.util.concurrent.TimeUnit; 027 028import javax.management.MBeanServer; 029import javax.management.ObjectName; 030 031import org.w3c.dom.Document; 032 033import org.apache.camel.CamelContext; 034import org.apache.camel.Endpoint; 035import org.apache.camel.Exchange; 036import org.apache.camel.ManagementStatisticsLevel; 037import org.apache.camel.Producer; 038import org.apache.camel.ProducerTemplate; 039import org.apache.camel.Route; 040import org.apache.camel.TimerListener; 041import org.apache.camel.api.management.ManagedResource; 042import org.apache.camel.api.management.mbean.ManagedCamelContextMBean; 043import org.apache.camel.api.management.mbean.ManagedProcessorMBean; 044import org.apache.camel.api.management.mbean.ManagedRouteMBean; 045import org.apache.camel.api.management.mbean.ManagedStepMBean; 046import org.apache.camel.model.Model; 047import org.apache.camel.model.RouteDefinition; 048import org.apache.camel.model.RouteTemplateDefinition; 049import org.apache.camel.model.RouteTemplatesDefinition; 050import org.apache.camel.model.RoutesDefinition; 051import org.apache.camel.model.rest.RestDefinition; 052import org.apache.camel.model.rest.RestsDefinition; 053import org.apache.camel.spi.ManagementStrategy; 054import org.apache.camel.spi.UnitOfWork; 055import org.apache.camel.support.CamelContextHelper; 056import org.apache.camel.support.PluginHelper; 057 058@ManagedResource(description = "Managed CamelContext") 059public class ManagedCamelContext extends ManagedPerformanceCounter implements TimerListener, ManagedCamelContextMBean { 060 061 private final CamelContext context; 062 private final LoadTriplet load = new LoadTriplet(); 063 private final LoadThroughput thp = new LoadThroughput(); 064 private final String jmxDomain; 065 private final boolean includeRouteTemplates; 066 private final boolean includeKamelets; 067 private Statistic remoteExchangesTotal; 068 private Statistic remoteExchangesCompleted; 069 private Statistic remoteExchangesFailed; 070 private Statistic remoteExchangesInflight; 071 072 public ManagedCamelContext(CamelContext context) { 073 this.context = context; 074 this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName(); 075 this.includeRouteTemplates = context.getManagementStrategy().getManagementAgent().getRegisterRoutesCreateByTemplate(); 076 this.includeKamelets = context.getManagementStrategy().getManagementAgent().getRegisterRoutesCreateByKamelet(); 077 } 078 079 @Override 080 public void init(ManagementStrategy strategy) { 081 super.init(strategy); 082 this.remoteExchangesTotal = new StatisticCounter(); 083 this.remoteExchangesCompleted = new StatisticCounter(); 084 this.remoteExchangesFailed = new StatisticCounter(); 085 this.remoteExchangesInflight = new StatisticCounter(); 086 boolean enabled = context.getManagementStrategy().getManagementAgent() != null 087 && context.getManagementStrategy().getManagementAgent().getStatisticsLevel() != ManagementStatisticsLevel.Off; 088 setStatisticsEnabled(enabled); 089 } 090 091 @Override 092 public void reset() { 093 super.reset(); 094 remoteExchangesTotal.reset(); 095 remoteExchangesCompleted.reset(); 096 remoteExchangesFailed.reset(); 097 remoteExchangesInflight.reset(); 098 } 099 100 @Override 101 public void completedExchange(Exchange exchange, long time) { 102 // the camel-context mbean is triggered for every route mbean 103 // so we must only trigger on the root level, otherwise the context mbean 104 // total counter will be incorrect. For example if an exchange is routed via 3 routes 105 // we should only count this as 1 instead of 3. 106 UnitOfWork uow = exchange.getUnitOfWork(); 107 if (uow != null) { 108 int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); 109 if (level <= 1) { 110 super.completedExchange(exchange, time); 111 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 112 remoteExchangesTotal.increment(); 113 remoteExchangesCompleted.increment(); 114 remoteExchangesInflight.decrement(); 115 } 116 } 117 } else { 118 super.completedExchange(exchange, time); 119 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 120 remoteExchangesTotal.increment(); 121 remoteExchangesCompleted.increment(); 122 remoteExchangesInflight.decrement(); 123 } 124 } 125 } 126 127 @Override 128 public void failedExchange(Exchange exchange) { 129 // the camel-context mbean is triggered for every route mbean 130 // so we must only trigger on the root level, otherwise the context mbean 131 // total counter will be incorrect. For example if an exchange is routed via 3 routes 132 // we should only count this as 1 instead of 3. 133 UnitOfWork uow = exchange.getUnitOfWork(); 134 if (uow != null) { 135 int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); 136 if (level <= 1) { 137 super.failedExchange(exchange); 138 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 139 remoteExchangesTotal.increment(); 140 remoteExchangesFailed.increment(); 141 remoteExchangesInflight.decrement(); 142 } 143 } 144 } else { 145 super.failedExchange(exchange); 146 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 147 remoteExchangesTotal.increment(); 148 remoteExchangesFailed.increment(); 149 remoteExchangesInflight.decrement(); 150 } 151 } 152 } 153 154 @Override 155 public void processExchange(Exchange exchange, String type) { 156 // the camel-context mbean is triggered for every route mbean 157 // so we must only trigger on the root level, otherwise the context mbean 158 // total counter will be incorrect. For example if an exchange is routed via 3 routes 159 // we should only count this as 1 instead of 3. 160 UnitOfWork uow = exchange.getUnitOfWork(); 161 if (uow != null) { 162 int level = uow.routeStackLevel(includeRouteTemplates, includeKamelets); 163 if (level <= 1) { 164 super.processExchange(exchange, type); 165 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 166 remoteExchangesInflight.increment(); 167 } 168 } 169 } else { 170 super.processExchange(exchange, type); 171 if (exchange.getFromEndpoint() != null && exchange.getFromEndpoint().isRemote()) { 172 remoteExchangesInflight.increment(); 173 } 174 } 175 } 176 177 public CamelContext getContext() { 178 return context; 179 } 180 181 @Override 182 public String getCamelId() { 183 return context.getName(); 184 } 185 186 @Override 187 public String getCamelDescription() { 188 return context.getDescription(); 189 } 190 191 @Override 192 public String getManagementName() { 193 return context.getManagementName(); 194 } 195 196 @Override 197 public String getCamelVersion() { 198 return context.getVersion(); 199 } 200 201 @Override 202 public String getProfile() { 203 return context.getCamelContextExtension().getProfile(); 204 } 205 206 @Override 207 public Boolean getAutoStartup() { 208 return context.isAutoStartup(); 209 } 210 211 @Override 212 public String getAutoStartupExcludePattern() { 213 return context.getAutoStartupExcludePattern(); 214 } 215 216 @Override 217 public String getState() { 218 return context.getStatus().name(); 219 } 220 221 @Override 222 public String getUptime() { 223 return CamelContextHelper.getUptime(context); 224 } 225 226 @Override 227 public long getUptimeMillis() { 228 return context.getUptime().toMillis(); 229 } 230 231 @Override 232 public String getManagementStatisticsLevel() { 233 if (context.getManagementStrategy().getManagementAgent() != null) { 234 return context.getManagementStrategy().getManagementAgent().getStatisticsLevel().name(); 235 } else { 236 return null; 237 } 238 } 239 240 @Override 241 public String getClassResolver() { 242 return context.getClassResolver().getClass().getName(); 243 } 244 245 @Override 246 public String getPackageScanClassResolver() { 247 return PluginHelper.getPackageScanClassResolver(context).getClass().getName(); 248 } 249 250 @Override 251 public String getApplicationContextClassName() { 252 if (context.getApplicationContextClassLoader() != null) { 253 return context.getApplicationContextClassLoader().getClass().getName(); 254 } else { 255 return null; 256 } 257 } 258 259 @Override 260 public String getHeadersMapFactoryClassName() { 261 return context.getCamelContextExtension().getHeadersMapFactory().getClass().getName(); 262 } 263 264 @Override 265 public Map<String, String> getGlobalOptions() { 266 if (context.getGlobalOptions().isEmpty()) { 267 return null; 268 } 269 return context.getGlobalOptions(); 270 } 271 272 @Override 273 public String getGlobalOption(String key) throws Exception { 274 return context.getGlobalOption(key); 275 } 276 277 @Override 278 public void setGlobalOption(String key, String value) throws Exception { 279 context.getGlobalOptions().put(key, value); 280 } 281 282 @Override 283 public Boolean getTracing() { 284 return context.isTracing(); 285 } 286 287 @Override 288 public void setTracing(Boolean tracing) { 289 context.setTracing(tracing); 290 } 291 292 public Integer getInflightExchanges() { 293 return (int) super.getExchangesInflight(); 294 } 295 296 @Override 297 public Integer getTotalRoutes() { 298 return context.getRoutesSize(); 299 } 300 301 @Override 302 public Integer getStartedRoutes() { 303 int started = 0; 304 for (Route route : context.getRoutes()) { 305 if (context.getRouteController().getRouteStatus(route.getId()).isStarted()) { 306 started++; 307 } 308 } 309 return started; 310 } 311 312 @Override 313 public void setTimeout(long timeout) { 314 context.getShutdownStrategy().setTimeout(timeout); 315 } 316 317 @Override 318 public long getTimeout() { 319 return context.getShutdownStrategy().getTimeout(); 320 } 321 322 @Override 323 public void setTimeUnit(TimeUnit timeUnit) { 324 context.getShutdownStrategy().setTimeUnit(timeUnit); 325 } 326 327 @Override 328 public TimeUnit getTimeUnit() { 329 return context.getShutdownStrategy().getTimeUnit(); 330 } 331 332 @Override 333 public void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout) { 334 context.getShutdownStrategy().setShutdownNowOnTimeout(shutdownNowOnTimeout); 335 } 336 337 @Override 338 public boolean isShutdownNowOnTimeout() { 339 return context.getShutdownStrategy().isShutdownNowOnTimeout(); 340 } 341 342 @Override 343 public String getLoad01() { 344 double load1 = load.getLoad1(); 345 if (Double.isNaN(load1)) { 346 // empty string if load statistics is disabled 347 return ""; 348 } else { 349 return String.format("%.2f", load1); 350 } 351 } 352 353 @Override 354 public String getLoad05() { 355 double load5 = load.getLoad5(); 356 if (Double.isNaN(load5)) { 357 // empty string if load statistics is disabled 358 return ""; 359 } else { 360 return String.format("%.2f", load5); 361 } 362 } 363 364 @Override 365 public String getLoad15() { 366 double load15 = load.getLoad15(); 367 if (Double.isNaN(load15)) { 368 // empty string if load statistics is disabled 369 return ""; 370 } else { 371 return String.format("%.2f", load15); 372 } 373 } 374 375 @Override 376 public String getThroughput() { 377 double d = thp.getThroughput(); 378 if (Double.isNaN(d)) { 379 // empty string if load statistics is disabled 380 return ""; 381 } else { 382 return String.format("%.2f", d); 383 } 384 } 385 386 @Override 387 public long getRemoteExchangesTotal() { 388 return remoteExchangesTotal.getValue(); 389 } 390 391 @Override 392 public long getRemoteExchangesCompleted() { 393 return remoteExchangesCompleted.getValue(); 394 } 395 396 @Override 397 public long getRemoteExchangesFailed() { 398 return remoteExchangesFailed.getValue(); 399 } 400 401 @Override 402 public long getRemoteExchangesInflight() { 403 return remoteExchangesInflight.getValue(); 404 } 405 406 @Override 407 public boolean isUseBreadcrumb() { 408 return context.isUseBreadcrumb(); 409 } 410 411 @Override 412 public boolean isAllowUseOriginalMessage() { 413 return context.isAllowUseOriginalMessage(); 414 } 415 416 @Override 417 public boolean isMessageHistory() { 418 return context.isMessageHistory() != null ? context.isMessageHistory() : false; 419 } 420 421 @Override 422 public boolean isLogMask() { 423 return context.isLogMask() != null ? context.isLogMask() : false; 424 } 425 426 @Override 427 public boolean isUseMDCLogging() { 428 return context.isUseMDCLogging(); 429 } 430 431 @Override 432 public boolean isUseDataType() { 433 return context.isUseDataType(); 434 } 435 436 @Override 437 public void onTimer() { 438 load.update(getInflightExchanges()); 439 thp.update(getExchangesTotal()); 440 } 441 442 @Override 443 public void start() throws Exception { 444 if (context.isSuspended()) { 445 context.resume(); 446 } else { 447 context.start(); 448 } 449 } 450 451 @Override 452 public void stop() throws Exception { 453 context.stop(); 454 } 455 456 @Override 457 public void restart() throws Exception { 458 context.stop(); 459 context.start(); 460 } 461 462 @Override 463 public void suspend() throws Exception { 464 context.suspend(); 465 } 466 467 @Override 468 public void resume() throws Exception { 469 if (context.isSuspended()) { 470 context.resume(); 471 } else { 472 throw new IllegalStateException("CamelContext is not suspended"); 473 } 474 } 475 476 @Override 477 public void startAllRoutes() throws Exception { 478 context.getRouteController().startAllRoutes(); 479 } 480 481 @Override 482 public boolean canSendToEndpoint(String endpointUri) { 483 try { 484 Endpoint endpoint = context.getEndpoint(endpointUri); 485 if (endpoint != null) { 486 try (Producer producer = endpoint.createProducer()) { 487 return producer != null; 488 } 489 } 490 } catch (Exception e) { 491 // ignore 492 } 493 494 return false; 495 } 496 497 @Override 498 public void sendBody(String endpointUri, Object body) throws Exception { 499 try (ProducerTemplate template = context.createProducerTemplate()) { 500 template.sendBody(endpointUri, body); 501 } 502 } 503 504 @Override 505 public void sendStringBody(String endpointUri, String body) throws Exception { 506 sendBody(endpointUri, body); 507 } 508 509 @Override 510 public void sendBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception { 511 try (ProducerTemplate template = context.createProducerTemplate()) { 512 template.sendBodyAndHeaders(endpointUri, body, headers); 513 } 514 } 515 516 @Override 517 public Object requestBody(String endpointUri, Object body) throws Exception { 518 try (ProducerTemplate template = context.createProducerTemplate()) { 519 return template.requestBody(endpointUri, body); 520 } 521 } 522 523 @Override 524 public Object requestStringBody(String endpointUri, String body) throws Exception { 525 return requestBody(endpointUri, body); 526 } 527 528 @Override 529 public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception { 530 try (ProducerTemplate template = context.createProducerTemplate()) { 531 return template.requestBodyAndHeaders(endpointUri, body, headers); 532 } 533 } 534 535 @Override 536 public String dumpRestsAsXml() throws Exception { 537 return dumpRestsAsXml(false); 538 } 539 540 @Override 541 public String dumpRestsAsXml(boolean resolvePlaceholders) throws Exception { 542 List<RestDefinition> rests = context.getCamelContextExtension().getContextPlugin(Model.class).getRestDefinitions(); 543 if (rests.isEmpty()) { 544 return null; 545 } 546 547 RestsDefinition def = new RestsDefinition(); 548 def.setRests(rests); 549 550 return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def, resolvePlaceholders, true); 551 } 552 553 @Override 554 public String dumpRoutesAsXml() throws Exception { 555 return dumpRoutesAsXml(false, true); 556 } 557 558 @Override 559 public String dumpRoutesAsXml(boolean resolvePlaceholders) throws Exception { 560 return dumpRoutesAsXml(resolvePlaceholders, true); 561 } 562 563 @Override 564 public String dumpRoutesAsXml(boolean resolvePlaceholders, boolean generatedIds) throws Exception { 565 List<RouteDefinition> routes = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteDefinitions(); 566 if (routes.isEmpty()) { 567 return null; 568 } 569 570 // use routes definition to dump the routes 571 RoutesDefinition def = new RoutesDefinition(); 572 def.setRoutes(routes); 573 574 // if we are debugging then ids is needed for the debugger 575 if (context.isDebugging()) { 576 generatedIds = true; 577 } 578 return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def, resolvePlaceholders, generatedIds); 579 } 580 581 @Override 582 public String dumpRoutesAsYaml() throws Exception { 583 return dumpRoutesAsYaml(false, false); 584 } 585 586 @Override 587 public String dumpRoutesAsYaml(boolean resolvePlaceholders) throws Exception { 588 return dumpRoutesAsYaml(resolvePlaceholders, false, true); 589 } 590 591 @Override 592 public String dumpRoutesAsYaml(boolean resolvePlaceholders, boolean uriAsParameters) throws Exception { 593 return dumpRoutesAsYaml(resolvePlaceholders, uriAsParameters, true); 594 } 595 596 @Override 597 public String dumpRoutesAsYaml(boolean resolvePlaceholders, boolean uriAsParameters, boolean generatedIds) 598 throws Exception { 599 List<RouteDefinition> routes = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteDefinitions(); 600 if (routes.isEmpty()) { 601 return null; 602 } 603 604 // use routes definition to dump the routes 605 RoutesDefinition def = new RoutesDefinition(); 606 def.setRoutes(routes); 607 608 // if we are debugging then ids is needed for the debugger 609 if (context.isDebugging()) { 610 generatedIds = true; 611 } 612 613 return PluginHelper.getModelToYAMLDumper(context).dumpModelAsYaml(context, def, resolvePlaceholders, uriAsParameters, 614 generatedIds); 615 } 616 617 @Override 618 public String dumpRouteTemplatesAsXml() throws Exception { 619 List<RouteTemplateDefinition> templates 620 = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteTemplateDefinitions(); 621 if (templates.isEmpty()) { 622 return null; 623 } 624 625 // use a route templates definition to dump the templates 626 RouteTemplatesDefinition def = new RouteTemplatesDefinition(); 627 def.setRouteTemplates(templates); 628 629 return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def); 630 } 631 632 @Override 633 public String dumpRoutesStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception { 634 StringBuilder sb = new StringBuilder(); 635 sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState())); 636 // use substring as we only want the attributes 637 String stat = dumpStatsAsXml(fullStats); 638 sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 639 sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 640 641 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 642 if (server != null) { 643 // gather all the routes for this CamelContext, which requires JMX 644 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 645 ObjectName query = ObjectName 646 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 647 Set<ObjectName> routes = server.queryNames(query, null); 648 649 List<ManagedProcessorMBean> processors = new ArrayList<>(); 650 if (includeProcessors) { 651 // gather all the processors for this CamelContext, which requires JMX 652 query = ObjectName.getInstance( 653 jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*"); 654 Set<ObjectName> names = server.queryNames(query, null); 655 for (ObjectName on : names) { 656 ManagedProcessorMBean processor = context.getManagementStrategy().getManagementAgent().newProxyClient(on, 657 ManagedProcessorMBean.class); 658 processors.add(processor); 659 } 660 } 661 processors.sort(new OrderProcessorMBeans()); 662 663 // loop the routes, and append the processor stats if needed 664 sb.append(" <routeStats>\n"); 665 for (ObjectName on : routes) { 666 ManagedRouteMBean route 667 = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class); 668 sb.append(" <routeStat") 669 .append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState())); 670 if (route.getSourceLocation() != null) { 671 sb.append(String.format(" sourceLocation=\"%s\"", route.getSourceLocation())); 672 } 673 674 // use substring as we only want the attributes 675 stat = route.dumpStatsAsXml(fullStats); 676 sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\""); 677 sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 678 679 // add processor details if needed 680 if (includeProcessors) { 681 sb.append(" <processorStats>\n"); 682 for (ManagedProcessorMBean processor : processors) { 683 int line = processor.getSourceLineNumber() != null ? processor.getSourceLineNumber() : -1; 684 // the processor must belong to this route 685 if (route.getRouteId().equals(processor.getRouteId())) { 686 sb.append(" <processorStat") 687 .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"", 688 processor.getProcessorId(), processor.getIndex(), processor.getState(), line)); 689 // use substring as we only want the attributes 690 stat = processor.dumpStatsAsXml(fullStats); 691 sb.append(" exchangesInflight=\"").append(processor.getExchangesInflight()).append("\""); 692 sb.append(" ").append(stat, 7, stat.length()).append("\n"); 693 } 694 } 695 sb.append(" </processorStats>\n"); 696 } 697 sb.append(" </routeStat>\n"); 698 } 699 sb.append(" </routeStats>\n"); 700 } 701 702 sb.append("</camelContextStat>"); 703 return sb.toString(); 704 } 705 706 @Override 707 public String dumpStepStatsAsXml(boolean fullStats) throws Exception { 708 StringBuilder sb = new StringBuilder(); 709 sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState())); 710 // use substring as we only want the attributes 711 String stat = dumpStatsAsXml(fullStats); 712 sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 713 sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 714 715 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 716 if (server != null) { 717 // gather all the routes for this CamelContext, which requires JMX 718 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 719 ObjectName query = ObjectName 720 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 721 Set<ObjectName> routes = server.queryNames(query, null); 722 723 List<ManagedProcessorMBean> steps = new ArrayList<>(); 724 // gather all the steps for this CamelContext, which requires JMX 725 query = ObjectName 726 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=steps,*"); 727 Set<ObjectName> names = server.queryNames(query, null); 728 for (ObjectName on : names) { 729 ManagedStepMBean step 730 = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedStepMBean.class); 731 steps.add(step); 732 } 733 steps.sort(new OrderProcessorMBeans()); 734 735 // loop the routes, and append the processor stats if needed 736 sb.append(" <routeStats>\n"); 737 for (ObjectName on : routes) { 738 ManagedRouteMBean route 739 = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class); 740 sb.append(" <routeStat") 741 .append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState())); 742 if (route.getSourceLocation() != null) { 743 sb.append(String.format(" sourceLocation=\"%s\"", route.getSourceLocation())); 744 } 745 746 // use substring as we only want the attributes 747 stat = route.dumpStatsAsXml(fullStats); 748 sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\""); 749 sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n"); 750 751 // add steps details if needed 752 sb.append(" <stepStats>\n"); 753 for (ManagedProcessorMBean step : steps) { 754 // the step must belong to this route 755 if (route.getRouteId().equals(step.getRouteId())) { 756 int line = step.getSourceLineNumber() != null ? step.getSourceLineNumber() : -1; 757 sb.append(" <stepStat") 758 .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"", 759 step.getProcessorId(), step.getIndex(), step.getState(), line)); 760 // use substring as we only want the attributes 761 stat = step.dumpStatsAsXml(fullStats); 762 sb.append(" exchangesInflight=\"").append(step.getExchangesInflight()).append("\""); 763 sb.append(" ").append(stat, 7, stat.length()).append("\n"); 764 } 765 sb.append(" </stepStats>\n"); 766 } 767 sb.append(" </stepStat>\n"); 768 } 769 sb.append(" </routeStats>\n"); 770 } 771 772 sb.append("</camelContextStat>"); 773 return sb.toString(); 774 } 775 776 @Override 777 public String dumpRoutesCoverageAsXml() throws Exception { 778 StringBuilder sb = new StringBuilder(); 779 sb.append("<camelContextRouteCoverage") 780 .append(String.format(" id=\"%s\" exchangesTotal=\"%s\" totalProcessingTime=\"%s\"", getCamelId(), 781 getExchangesTotal(), getTotalProcessingTime())) 782 .append(">\n"); 783 784 String xml = dumpRoutesAsXml(false, true); 785 if (xml != null) { 786 // use the coverage xml parser to dump the routes and enrich with coverage stats 787 Document dom = RouteCoverageXmlParser.parseXml(context, new ByteArrayInputStream(xml.getBytes())); 788 // convert dom back to xml 789 String converted = context.getTypeConverter().convertTo(String.class, dom); 790 sb.append(converted); 791 } 792 793 sb.append("\n</camelContextRouteCoverage>"); 794 return sb.toString(); 795 } 796 797 @Override 798 public boolean createEndpoint(String uri) throws Exception { 799 if (context.hasEndpoint(uri) != null) { 800 // endpoint already exists 801 return false; 802 } 803 804 Endpoint endpoint = context.getEndpoint(uri); 805 if (endpoint != null) { 806 // ensure endpoint is registered, as the management strategy could have been configured to not always 807 // register new endpoints in JMX, so we need to check if its registered, and if not register it manually 808 ObjectName on 809 = context.getManagementStrategy().getManagementObjectNameStrategy().getObjectNameForEndpoint(endpoint); 810 if (on != null && !context.getManagementStrategy().getManagementAgent().isRegistered(on)) { 811 // register endpoint as mbean 812 Object me = context.getManagementStrategy().getManagementObjectStrategy().getManagedObjectForEndpoint(context, 813 endpoint); 814 context.getManagementStrategy().getManagementAgent().register(me, on); 815 } 816 return true; 817 } else { 818 return false; 819 } 820 } 821 822 @Override 823 public int removeEndpoints(String pattern) throws Exception { 824 // endpoints is always removed from JMX if removed from context 825 Collection<Endpoint> removed = context.removeEndpoints(pattern); 826 return removed.size(); 827 } 828 829 @Override 830 public void reset(boolean includeRoutes) throws Exception { 831 reset(); 832 load.reset(); 833 thp.reset(); 834 835 // and now reset all routes for this route 836 if (includeRoutes) { 837 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 838 if (server != null) { 839 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 840 ObjectName query = ObjectName 841 .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 842 Set<ObjectName> names = server.queryNames(query, null); 843 for (ObjectName name : names) { 844 server.invoke(name, "reset", new Object[] { true }, new String[] { "boolean" }); 845 } 846 } 847 } 848 } 849 850 @Override 851 public Set<String> componentNames() throws Exception { 852 return context.getComponentNames(); 853 } 854 855 @Override 856 public Set<String> languageNames() throws Exception { 857 return context.getLanguageNames(); 858 } 859 860 @Override 861 public Set<String> dataFormatNames() throws Exception { 862 return context.getDataFormatNames(); 863 } 864 865 /** 866 * Used for sorting the processor mbeans accordingly to their index. 867 */ 868 private static final class OrderProcessorMBeans implements Comparator<ManagedProcessorMBean> { 869 870 @Override 871 public int compare(ManagedProcessorMBean o1, ManagedProcessorMBean o2) { 872 return o1.getIndex().compareTo(o2.getIndex()); 873 } 874 } 875 876}