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.io.InputStream; 021import java.net.URLDecoder; 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.Comparator; 025import java.util.List; 026import java.util.Map; 027import java.util.Properties; 028import java.util.Set; 029import java.util.concurrent.TimeUnit; 030import java.util.concurrent.atomic.AtomicBoolean; 031import javax.management.MBeanServer; 032import javax.management.ObjectName; 033import javax.management.openmbean.CompositeData; 034import javax.management.openmbean.CompositeDataSupport; 035import javax.management.openmbean.CompositeType; 036import javax.management.openmbean.TabularData; 037import javax.management.openmbean.TabularDataSupport; 038 039import org.w3c.dom.Document; 040 041import org.apache.camel.CamelContext; 042import org.apache.camel.CatalogCamelContext; 043import org.apache.camel.Endpoint; 044import org.apache.camel.ManagementStatisticsLevel; 045import org.apache.camel.Producer; 046import org.apache.camel.ProducerTemplate; 047import org.apache.camel.Route; 048import org.apache.camel.RuntimeCamelException; 049import org.apache.camel.TimerListener; 050import org.apache.camel.api.management.ManagedResource; 051import org.apache.camel.api.management.mbean.CamelOpenMBeanTypes; 052import org.apache.camel.api.management.mbean.ManagedCamelContextMBean; 053import org.apache.camel.api.management.mbean.ManagedProcessorMBean; 054import org.apache.camel.api.management.mbean.ManagedRouteMBean; 055import org.apache.camel.api.management.mbean.ManagedStepMBean; 056import org.apache.camel.model.ModelCamelContext; 057import org.apache.camel.model.ModelHelper; 058import org.apache.camel.model.RouteDefinition; 059import org.apache.camel.model.RoutesDefinition; 060import org.apache.camel.model.rest.RestDefinition; 061import org.apache.camel.model.rest.RestsDefinition; 062import org.apache.camel.spi.ManagementStrategy; 063import org.apache.camel.support.JSonSchemaHelper; 064import org.apache.camel.util.XmlLineNumberParser; 065import org.slf4j.Logger; 066import org.slf4j.LoggerFactory; 067 068@ManagedResource(description = "Managed CamelContext") 069public class ManagedCamelContext extends ManagedPerformanceCounter implements TimerListener, ManagedCamelContextMBean { 070 071 private static final Logger LOG = LoggerFactory.getLogger(ManagedCamelContext.class); 072 073 private final ModelCamelContext context; 074 private final LoadTriplet load = new LoadTriplet(); 075 private final String jmxDomain; 076 077 public ManagedCamelContext(ModelCamelContext context) { 078 this.context = context; 079 this.jmxDomain = context.getManagementStrategy().getManagementAgent().getMBeanObjectDomainName(); 080 } 081 082 @Override 083 public void init(ManagementStrategy strategy) { 084 super.init(strategy); 085 boolean enabled = context.getManagementStrategy().getManagementAgent() != null && context.getManagementStrategy().getManagementAgent().getStatisticsLevel() != ManagementStatisticsLevel.Off; 086 setStatisticsEnabled(enabled); 087 } 088 089 public CamelContext getContext() { 090 return context; 091 } 092 093 public String getCamelId() { 094 return context.getName(); 095 } 096 097 public String getManagementName() { 098 return context.getManagementName(); 099 } 100 101 public String getCamelVersion() { 102 return context.getVersion(); 103 } 104 105 public String getState() { 106 return context.getStatus().name(); 107 } 108 109 public String getUptime() { 110 return context.getUptime(); 111 } 112 113 public long getUptimeMillis() { 114 return context.getUptimeMillis(); 115 } 116 117 public String getManagementStatisticsLevel() { 118 if (context.getManagementStrategy().getManagementAgent() != null) { 119 return context.getManagementStrategy().getManagementAgent().getStatisticsLevel().name(); 120 } else { 121 return null; 122 } 123 } 124 125 public String getClassResolver() { 126 return context.getClassResolver().getClass().getName(); 127 } 128 129 public String getPackageScanClassResolver() { 130 return context.getPackageScanClassResolver().getClass().getName(); 131 } 132 133 public String getApplicationContextClassName() { 134 if (context.getApplicationContextClassLoader() != null) { 135 return context.getApplicationContextClassLoader().getClass().getName(); 136 } else { 137 return null; 138 } 139 } 140 141 @Override 142 public String getHeadersMapFactoryClassName() { 143 return context.getHeadersMapFactory().getClass().getName(); 144 } 145 146 @Override 147 public Map<String, String> getGlobalOptions() { 148 if (context.getGlobalOptions().isEmpty()) { 149 return null; 150 } 151 return context.getGlobalOptions(); 152 } 153 154 @Override 155 public String getGlobalOption(String key) throws Exception { 156 return context.getGlobalOption(key); 157 } 158 159 @Override 160 public void setGlobalOption(String key, String value) throws Exception { 161 context.getGlobalOptions().put(key, value); 162 } 163 164 public Boolean getTracing() { 165 return context.isTracing(); 166 } 167 168 public void setTracing(Boolean tracing) { 169 context.setTracing(tracing); 170 } 171 172 public Integer getInflightExchanges() { 173 return (int) super.getExchangesInflight(); 174 } 175 176 public Integer getTotalRoutes() { 177 return context.getRoutes().size(); 178 } 179 180 public Integer getStartedRoutes() { 181 int started = 0; 182 for (Route route : context.getRoutes()) { 183 if (context.getRouteController().getRouteStatus(route.getId()).isStarted()) { 184 started++; 185 } 186 } 187 return started; 188 } 189 190 public void setTimeout(long timeout) { 191 context.getShutdownStrategy().setTimeout(timeout); 192 } 193 194 public long getTimeout() { 195 return context.getShutdownStrategy().getTimeout(); 196 } 197 198 public void setTimeUnit(TimeUnit timeUnit) { 199 context.getShutdownStrategy().setTimeUnit(timeUnit); 200 } 201 202 public TimeUnit getTimeUnit() { 203 return context.getShutdownStrategy().getTimeUnit(); 204 } 205 206 public void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout) { 207 context.getShutdownStrategy().setShutdownNowOnTimeout(shutdownNowOnTimeout); 208 } 209 210 public boolean isShutdownNowOnTimeout() { 211 return context.getShutdownStrategy().isShutdownNowOnTimeout(); 212 } 213 214 public String getLoad01() { 215 double load1 = load.getLoad1(); 216 if (Double.isNaN(load1)) { 217 // empty string if load statistics is disabled 218 return ""; 219 } else { 220 return String.format("%.2f", load1); 221 } 222 } 223 224 public String getLoad05() { 225 double load5 = load.getLoad5(); 226 if (Double.isNaN(load5)) { 227 // empty string if load statistics is disabled 228 return ""; 229 } else { 230 return String.format("%.2f", load5); 231 } 232 } 233 234 public String getLoad15() { 235 double load15 = load.getLoad15(); 236 if (Double.isNaN(load15)) { 237 // empty string if load statistics is disabled 238 return ""; 239 } else { 240 return String.format("%.2f", load15); 241 } 242 } 243 244 public boolean isUseBreadcrumb() { 245 return context.isUseBreadcrumb(); 246 } 247 248 public boolean isAllowUseOriginalMessage() { 249 return context.isAllowUseOriginalMessage(); 250 } 251 252 public boolean isMessageHistory() { 253 return context.isMessageHistory() != null ? context.isMessageHistory() : false; 254 } 255 256 public boolean isLogMask() { 257 return context.isLogMask() != null ? context.isLogMask() : false; 258 } 259 260 public boolean isUseMDCLogging() { 261 return context.isUseMDCLogging(); 262 } 263 264 public boolean isUseDataType() { 265 return context.isUseDataType(); 266 } 267 268 public void onTimer() { 269 load.update(getInflightExchanges()); 270 } 271 272 public void start() throws Exception { 273 if (context.isSuspended()) { 274 context.resume(); 275 } else { 276 context.start(); 277 } 278 } 279 280 public void stop() throws Exception { 281 context.stop(); 282 } 283 284 public void restart() throws Exception { 285 context.stop(); 286 context.start(); 287 } 288 289 public void suspend() throws Exception { 290 context.suspend(); 291 } 292 293 public void resume() throws Exception { 294 if (context.isSuspended()) { 295 context.resume(); 296 } else { 297 throw new IllegalStateException("CamelContext is not suspended"); 298 } 299 } 300 301 public void startAllRoutes() throws Exception { 302 context.getRouteController().startAllRoutes(); 303 } 304 305 public boolean canSendToEndpoint(String endpointUri) { 306 try { 307 Endpoint endpoint = context.getEndpoint(endpointUri); 308 if (endpoint != null) { 309 Producer producer = endpoint.createProducer(); 310 return producer != null; 311 } 312 } catch (Exception e) { 313 // ignore 314 } 315 316 return false; 317 } 318 319 public void sendBody(String endpointUri, Object body) throws Exception { 320 ProducerTemplate template = context.createProducerTemplate(); 321 try { 322 template.sendBody(endpointUri, body); 323 } finally { 324 template.stop(); 325 } 326 } 327 328 public void sendStringBody(String endpointUri, String body) throws Exception { 329 sendBody(endpointUri, body); 330 } 331 332 public void sendBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception { 333 ProducerTemplate template = context.createProducerTemplate(); 334 try { 335 template.sendBodyAndHeaders(endpointUri, body, headers); 336 } finally { 337 template.stop(); 338 } 339 } 340 341 public Object requestBody(String endpointUri, Object body) throws Exception { 342 ProducerTemplate template = context.createProducerTemplate(); 343 Object answer = null; 344 try { 345 answer = template.requestBody(endpointUri, body); 346 } finally { 347 template.stop(); 348 } 349 return answer; 350 } 351 352 public Object requestStringBody(String endpointUri, String body) throws Exception { 353 return requestBody(endpointUri, body); 354 } 355 356 public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception { 357 ProducerTemplate template = context.createProducerTemplate(); 358 Object answer = null; 359 try { 360 answer = template.requestBodyAndHeaders(endpointUri, body, headers); 361 } finally { 362 template.stop(); 363 } 364 return answer; 365 } 366 367 public String dumpRestsAsXml() throws Exception { 368 return dumpRestsAsXml(false); 369 } 370 371 @Override 372 public String dumpRestsAsXml(boolean resolvePlaceholders) throws Exception { 373 List<RestDefinition> rests = context.getRestDefinitions(); 374 if (rests.isEmpty()) { 375 return null; 376 } 377 378 // use a routes definition to dump the rests 379 RestsDefinition def = new RestsDefinition(); 380 def.setRests(rests); 381 String xml = ModelHelper.dumpModelAsXml(context, def); 382 383 // if resolving placeholders we parse the xml, and resolve the property placeholders during parsing 384 if (resolvePlaceholders) { 385 final AtomicBoolean changed = new AtomicBoolean(); 386 InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8")); 387 Document dom = XmlLineNumberParser.parseXml(is, new XmlLineNumberParser.XmlTextTransformer() { 388 @Override 389 public String transform(String text) { 390 try { 391 String after = getContext().resolvePropertyPlaceholders(text); 392 if (!changed.get()) { 393 changed.set(!text.equals(after)); 394 } 395 return after; 396 } catch (Exception e) { 397 // ignore 398 return text; 399 } 400 } 401 }); 402 // okay there were some property placeholder replaced so re-create the model 403 if (changed.get()) { 404 xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom); 405 RestsDefinition copy = ModelHelper.createModelFromXml(context, xml, RestsDefinition.class); 406 xml = ModelHelper.dumpModelAsXml(context, copy); 407 } 408 } 409 410 return xml; 411 } 412 413 public String dumpRoutesAsXml() throws Exception { 414 return dumpRoutesAsXml(false); 415 } 416 417 @Override 418 public String dumpRoutesAsXml(boolean resolvePlaceholders) throws Exception { 419 List<RouteDefinition> routes = context.getRouteDefinitions(); 420 if (routes.isEmpty()) { 421 return null; 422 } 423 424 // use a routes definition to dump the routes 425 RoutesDefinition def = new RoutesDefinition(); 426 def.setRoutes(routes); 427 String xml = ModelHelper.dumpModelAsXml(context, def); 428 429 // if resolving placeholders we parse the xml, and resolve the property placeholders during parsing 430 if (resolvePlaceholders) { 431 final AtomicBoolean changed = new AtomicBoolean(); 432 InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8")); 433 Document dom = XmlLineNumberParser.parseXml(is, new XmlLineNumberParser.XmlTextTransformer() { 434 @Override 435 public String transform(String text) { 436 try { 437 String after = getContext().resolvePropertyPlaceholders(text); 438 if (!changed.get()) { 439 changed.set(!text.equals(after)); 440 } 441 return after; 442 } catch (Exception e) { 443 // ignore 444 return text; 445 } 446 } 447 }); 448 // okay there were some property placeholder replaced so re-create the model 449 if (changed.get()) { 450 xml = context.getTypeConverter().mandatoryConvertTo(String.class, dom); 451 RoutesDefinition copy = ModelHelper.createModelFromXml(context, xml, RoutesDefinition.class); 452 xml = ModelHelper.dumpModelAsXml(context, copy); 453 } 454 } 455 456 return xml; 457 } 458 459 public void addOrUpdateRoutesFromXml(String xml) throws Exception { 460 // do not decode so we function as before 461 addOrUpdateRoutesFromXml(xml, false); 462 } 463 464 public void addOrUpdateRoutesFromXml(String xml, boolean urlDecode) throws Exception { 465 // decode String as it may have been encoded, from its xml source 466 if (urlDecode) { 467 xml = URLDecoder.decode(xml, "UTF-8"); 468 } 469 470 InputStream is = context.getTypeConverter().mandatoryConvertTo(InputStream.class, xml); 471 try { 472 // add will remove existing route first 473 context.addRouteDefinitions(is); 474 } catch (Exception e) { 475 // log the error as warn as the management api may be invoked remotely over JMX which does not propagate such exception 476 String msg = "Error updating routes from xml: " + xml + " due: " + e.getMessage(); 477 LOG.warn(msg, e); 478 throw e; 479 } 480 } 481 482 public String dumpRoutesStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception { 483 StringBuilder sb = new StringBuilder(); 484 sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState())); 485 // use substring as we only want the attributes 486 String stat = dumpStatsAsXml(fullStats); 487 sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 488 sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n"); 489 490 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 491 if (server != null) { 492 // gather all the routes for this CamelContext, which requires JMX 493 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 494 ObjectName query = ObjectName.getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 495 Set<ObjectName> routes = server.queryNames(query, null); 496 497 List<ManagedProcessorMBean> processors = new ArrayList<>(); 498 if (includeProcessors) { 499 // gather all the processors for this CamelContext, which requires JMX 500 query = ObjectName.getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*"); 501 Set<ObjectName> names = server.queryNames(query, null); 502 for (ObjectName on : names) { 503 ManagedProcessorMBean processor = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedProcessorMBean.class); 504 processors.add(processor); 505 } 506 } 507 processors.sort(new OrderProcessorMBeans()); 508 509 // loop the routes, and append the processor stats if needed 510 sb.append(" <routeStats>\n"); 511 for (ObjectName on : routes) { 512 ManagedRouteMBean route = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class); 513 sb.append(" <routeStat").append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState())); 514 // use substring as we only want the attributes 515 stat = route.dumpStatsAsXml(fullStats); 516 sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\""); 517 sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n"); 518 519 // add processor details if needed 520 if (includeProcessors) { 521 sb.append(" <processorStats>\n"); 522 for (ManagedProcessorMBean processor : processors) { 523 // the processor must belong to this route 524 if (route.getRouteId().equals(processor.getRouteId())) { 525 sb.append(" <processorStat").append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\"", processor.getProcessorId(), processor.getIndex(), processor.getState())); 526 // use substring as we only want the attributes 527 stat = processor.dumpStatsAsXml(fullStats); 528 sb.append(" exchangesInflight=\"").append(processor.getExchangesInflight()).append("\""); 529 sb.append(" ").append(stat.substring(7)).append("\n"); 530 } 531 } 532 sb.append(" </processorStats>\n"); 533 } 534 sb.append(" </routeStat>\n"); 535 } 536 sb.append(" </routeStats>\n"); 537 } 538 539 sb.append("</camelContextStat>"); 540 return sb.toString(); 541 } 542 543 public String dumpStepStatsAsXml(boolean fullStats) throws Exception { 544 StringBuilder sb = new StringBuilder(); 545 sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState())); 546 // use substring as we only want the attributes 547 String stat = dumpStatsAsXml(fullStats); 548 sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\""); 549 sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n"); 550 551 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 552 if (server != null) { 553 // gather all the routes for this CamelContext, which requires JMX 554 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 555 ObjectName query = ObjectName.getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 556 Set<ObjectName> routes = server.queryNames(query, null); 557 558 List<ManagedProcessorMBean> steps = new ArrayList<>(); 559 // gather all the steps for this CamelContext, which requires JMX 560 query = ObjectName.getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=steps,*"); 561 Set<ObjectName> names = server.queryNames(query, null); 562 for (ObjectName on : names) { 563 ManagedStepMBean step = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedStepMBean.class); 564 steps.add(step); 565 } 566 steps.sort(new OrderProcessorMBeans()); 567 568 // loop the routes, and append the processor stats if needed 569 sb.append(" <routeStats>\n"); 570 for (ObjectName on : routes) { 571 ManagedRouteMBean route = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class); 572 sb.append(" <routeStat").append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState())); 573 // use substring as we only want the attributes 574 stat = route.dumpStatsAsXml(fullStats); 575 sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\""); 576 sb.append(" ").append(stat.substring(7, stat.length() - 2)).append(">\n"); 577 578 // add steps details if needed 579 sb.append(" <stepStats>\n"); 580 for (ManagedProcessorMBean processor : steps) { 581 // the step must belong to this route 582 if (route.getRouteId().equals(processor.getRouteId())) { 583 sb.append(" <stepStat").append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\"", processor.getProcessorId(), processor.getIndex(), processor.getState())); 584 // use substring as we only want the attributes 585 stat = processor.dumpStatsAsXml(fullStats); 586 sb.append(" exchangesInflight=\"").append(processor.getExchangesInflight()).append("\""); 587 sb.append(" ").append(stat.substring(7)).append("\n"); 588 } 589 sb.append(" </stepStats>\n"); 590 } 591 sb.append(" </stepStat>\n"); 592 } 593 sb.append(" </routeStats>\n"); 594 } 595 596 sb.append("</camelContextStat>"); 597 return sb.toString(); 598 } 599 600 public String dumpRoutesCoverageAsXml() throws Exception { 601 StringBuilder sb = new StringBuilder(); 602 sb.append("<camelContextRouteCoverage") 603 .append(String.format(" id=\"%s\" exchangesTotal=\"%s\" totalProcessingTime=\"%s\"", getCamelId(), getExchangesTotal(), getTotalProcessingTime())) 604 .append(">\n"); 605 606 String xml = dumpRoutesAsXml(); 607 if (xml != null) { 608 // use the coverage xml parser to dump the routes and enrich with coverage stats 609 Document dom = RouteCoverageXmlParser.parseXml(context, new ByteArrayInputStream(xml.getBytes())); 610 // convert dom back to xml 611 String converted = context.getTypeConverter().convertTo(String.class, dom); 612 sb.append(converted); 613 } 614 615 sb.append("\n</camelContextRouteCoverage>"); 616 return sb.toString(); 617 } 618 619 public boolean createEndpoint(String uri) throws Exception { 620 if (context.hasEndpoint(uri) != null) { 621 // endpoint already exists 622 return false; 623 } 624 625 Endpoint endpoint = context.getEndpoint(uri); 626 if (endpoint != null) { 627 // ensure endpoint is registered, as the management strategy could have been configured to not always 628 // register new endpoints in JMX, so we need to check if its registered, and if not register it manually 629 ObjectName on = context.getManagementStrategy().getManagementObjectNameStrategy().getObjectNameForEndpoint(endpoint); 630 if (on != null && !context.getManagementStrategy().getManagementAgent().isRegistered(on)) { 631 // register endpoint as mbean 632 Object me = context.getManagementStrategy().getManagementObjectStrategy().getManagedObjectForEndpoint(context, endpoint); 633 context.getManagementStrategy().getManagementAgent().register(me, on); 634 } 635 return true; 636 } else { 637 return false; 638 } 639 } 640 641 public int removeEndpoints(String pattern) throws Exception { 642 // endpoints is always removed from JMX if removed from context 643 Collection<Endpoint> removed = context.removeEndpoints(pattern); 644 return removed.size(); 645 } 646 647 public Map<String, Properties> findEips() throws Exception { 648 return context.adapt(CatalogCamelContext.class).findEips(); 649 } 650 651 public List<String> findEipNames() throws Exception { 652 Map<String, Properties> map = findEips(); 653 return new ArrayList<>(map.keySet()); 654 } 655 656 public TabularData listEips() throws Exception { 657 try { 658 // find all EIPs 659 Map<String, Properties> eips = context.adapt(CatalogCamelContext.class).findEips(); 660 661 TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.listEipsTabularType()); 662 663 // gather EIP detail for each eip 664 for (Map.Entry<String, Properties> entry : eips.entrySet()) { 665 String name = entry.getKey(); 666 String title = (String) entry.getValue().get("title"); 667 String description = (String) entry.getValue().get("description"); 668 String label = (String) entry.getValue().get("label"); 669 String type = (String) entry.getValue().get("class"); 670 String status = ModelCamelContextHelper.isEipInUse(context, name) ? "in use" : "on classpath"; 671 CompositeType ct = CamelOpenMBeanTypes.listEipsCompositeType(); 672 CompositeData data = new CompositeDataSupport(ct, new String[]{"name", "title", "description", "label", "status", "type"}, 673 new Object[]{name, title, description, label, status, type}); 674 answer.put(data); 675 } 676 return answer; 677 } catch (Exception e) { 678 throw RuntimeCamelException.wrapRuntimeCamelException(e); 679 } 680 } 681 682 public Map<String, Properties> findComponents() throws Exception { 683 Map<String, Properties> answer = context.adapt(CatalogCamelContext.class).findComponents(); 684 for (Map.Entry<String, Properties> entry : answer.entrySet()) { 685 if (entry.getValue() != null) { 686 // remove component as its not serializable over JMX 687 entry.getValue().remove("component"); 688 // .. and components which just list all the components in the JAR/bundle and that is verbose and not needed 689 entry.getValue().remove("components"); 690 } 691 } 692 return answer; 693 } 694 695 public String createRouteStaticEndpointJson() { 696 return createRouteStaticEndpointJson(true); 697 } 698 699 public String createRouteStaticEndpointJson(boolean includeDynamic) { 700 return context.adapt(CatalogCamelContext.class).createRouteStaticEndpointJson(null, includeDynamic); 701 } 702 703 public List<String> findComponentNames() throws Exception { 704 Map<String, Properties> map = findComponents(); 705 return new ArrayList<>(map.keySet()); 706 } 707 708 @Override 709 public TabularData listComponents() throws Exception { 710 try { 711 // find all components 712 Map<String, Properties> components = context.adapt(CatalogCamelContext.class).findComponents(); 713 714 TabularData answer = new TabularDataSupport(CamelOpenMBeanTypes.listComponentsTabularType()); 715 716 // gather component detail for each component 717 for (Map.Entry<String, Properties> entry : components.entrySet()) { 718 String name = entry.getKey(); 719 String title = null; 720 String syntax = null; 721 String description = null; 722 String label = null; 723 String deprecated = null; 724 String secret = null; 725 String status = context.hasComponent(name) != null ? "in use" : "on classpath"; 726 String type = (String) entry.getValue().get("class"); 727 String groupId = null; 728 String artifactId = null; 729 String version = null; 730 731 // a component may have been given a different name, so resolve its default name by its java type 732 // as we can find the component json information from the default component name 733 String defaultName = context.adapt(CatalogCamelContext.class).resolveComponentDefaultName(type); 734 String target = defaultName != null ? defaultName : name; 735 736 // load component json data, and parse it to gather the component meta-data 737 String json = context.adapt(CatalogCamelContext.class).getComponentParameterJsonSchema(target); 738 List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("component", json, false); 739 for (Map<String, String> row : rows) { 740 if (row.containsKey("title")) { 741 title = row.get("title"); 742 } else if (row.containsKey("syntax")) { 743 syntax = row.get("syntax"); 744 } else if (row.containsKey("description")) { 745 description = row.get("description"); 746 } else if (row.containsKey("label")) { 747 label = row.get("label"); 748 } else if (row.containsKey("deprecated")) { 749 deprecated = row.get("deprecated"); 750 } else if (row.containsKey("secret")) { 751 secret = row.get("secret"); 752 } else if (row.containsKey("javaType")) { 753 type = row.get("javaType"); 754 } else if (row.containsKey("groupId")) { 755 groupId = row.get("groupId"); 756 } else if (row.containsKey("artifactId")) { 757 artifactId = row.get("artifactId"); 758 } else if (row.containsKey("version")) { 759 version = row.get("version"); 760 } 761 } 762 763 CompositeType ct = CamelOpenMBeanTypes.listComponentsCompositeType(); 764 CompositeData data = new CompositeDataSupport(ct, 765 new String[]{"name", "title", "syntax", "description", "label", "deprecated", "secret", "status", "type", "groupId", "artifactId", "version"}, 766 new Object[]{name, title, syntax, description, label, deprecated, secret, status, type, groupId, artifactId, version}); 767 answer.put(data); 768 } 769 return answer; 770 } catch (Exception e) { 771 throw RuntimeCamelException.wrapRuntimeCamelException(e); 772 } 773 } 774 775 public String componentParameterJsonSchema(String componentName) throws Exception { 776 return context.adapt(CatalogCamelContext.class).getComponentParameterJsonSchema(componentName); 777 } 778 779 public String dataFormatParameterJsonSchema(String dataFormatName) throws Exception { 780 return context.adapt(CatalogCamelContext.class).getDataFormatParameterJsonSchema(dataFormatName); 781 } 782 783 public String languageParameterJsonSchema(String languageName) throws Exception { 784 return context.adapt(CatalogCamelContext.class).getLanguageParameterJsonSchema(languageName); 785 } 786 787 public String eipParameterJsonSchema(String eipName) throws Exception { 788 return context.adapt(CatalogCamelContext.class).getEipParameterJsonSchema(eipName); 789 } 790 791 public String explainEipJson(String nameOrId, boolean includeAllOptions) { 792 return context.adapt(CatalogCamelContext.class).explainEipJson(nameOrId, includeAllOptions); 793 } 794 795 public String explainComponentJson(String componentName, boolean includeAllOptions) throws Exception { 796 return context.adapt(CatalogCamelContext.class).explainComponentJson(componentName, includeAllOptions); 797 } 798 799 public String explainEndpointJson(String uri, boolean includeAllOptions) throws Exception { 800 return context.adapt(CatalogCamelContext.class).explainEndpointJson(uri, includeAllOptions); 801 } 802 803 public void reset(boolean includeRoutes) throws Exception { 804 reset(); 805 806 // and now reset all routes for this route 807 if (includeRoutes) { 808 MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer(); 809 if (server != null) { 810 String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : ""; 811 ObjectName query = ObjectName.getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*"); 812 Set<ObjectName> names = server.queryNames(query, null); 813 for (ObjectName name : names) { 814 server.invoke(name, "reset", new Object[]{true}, new String[]{"boolean"}); 815 } 816 } 817 } 818 } 819 820 /** 821 * Used for sorting the processor mbeans accordingly to their index. 822 */ 823 private static final class OrderProcessorMBeans implements Comparator<ManagedProcessorMBean> { 824 825 @Override 826 public int compare(ManagedProcessorMBean o1, ManagedProcessorMBean o2) { 827 return o1.getIndex().compareTo(o2.getIndex()); 828 } 829 } 830 831}