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}