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