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 String getState() {
208        return context.getStatus().name();
209    }
210
211    @Override
212    public String getUptime() {
213        return CamelContextHelper.getUptime(context);
214    }
215
216    @Override
217    public long getUptimeMillis() {
218        return context.getUptime().toMillis();
219    }
220
221    @Override
222    public String getManagementStatisticsLevel() {
223        if (context.getManagementStrategy().getManagementAgent() != null) {
224            return context.getManagementStrategy().getManagementAgent().getStatisticsLevel().name();
225        } else {
226            return null;
227        }
228    }
229
230    @Override
231    public String getClassResolver() {
232        return context.getClassResolver().getClass().getName();
233    }
234
235    @Override
236    public String getPackageScanClassResolver() {
237        return PluginHelper.getPackageScanClassResolver(context).getClass().getName();
238    }
239
240    @Override
241    public String getApplicationContextClassName() {
242        if (context.getApplicationContextClassLoader() != null) {
243            return context.getApplicationContextClassLoader().getClass().getName();
244        } else {
245            return null;
246        }
247    }
248
249    @Override
250    public String getHeadersMapFactoryClassName() {
251        return context.getCamelContextExtension().getHeadersMapFactory().getClass().getName();
252    }
253
254    @Override
255    public Map<String, String> getGlobalOptions() {
256        if (context.getGlobalOptions().isEmpty()) {
257            return null;
258        }
259        return context.getGlobalOptions();
260    }
261
262    @Override
263    public String getGlobalOption(String key) throws Exception {
264        return context.getGlobalOption(key);
265    }
266
267    @Override
268    public void setGlobalOption(String key, String value) throws Exception {
269        context.getGlobalOptions().put(key, value);
270    }
271
272    @Override
273    public Boolean getTracing() {
274        return context.isTracing();
275    }
276
277    @Override
278    public void setTracing(Boolean tracing) {
279        context.setTracing(tracing);
280    }
281
282    public Integer getInflightExchanges() {
283        return (int) super.getExchangesInflight();
284    }
285
286    @Override
287    public Integer getTotalRoutes() {
288        return context.getRoutesSize();
289    }
290
291    @Override
292    public Integer getStartedRoutes() {
293        int started = 0;
294        for (Route route : context.getRoutes()) {
295            if (context.getRouteController().getRouteStatus(route.getId()).isStarted()) {
296                started++;
297            }
298        }
299        return started;
300    }
301
302    @Override
303    public void setTimeout(long timeout) {
304        context.getShutdownStrategy().setTimeout(timeout);
305    }
306
307    @Override
308    public long getTimeout() {
309        return context.getShutdownStrategy().getTimeout();
310    }
311
312    @Override
313    public void setTimeUnit(TimeUnit timeUnit) {
314        context.getShutdownStrategy().setTimeUnit(timeUnit);
315    }
316
317    @Override
318    public TimeUnit getTimeUnit() {
319        return context.getShutdownStrategy().getTimeUnit();
320    }
321
322    @Override
323    public void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout) {
324        context.getShutdownStrategy().setShutdownNowOnTimeout(shutdownNowOnTimeout);
325    }
326
327    @Override
328    public boolean isShutdownNowOnTimeout() {
329        return context.getShutdownStrategy().isShutdownNowOnTimeout();
330    }
331
332    @Override
333    public String getLoad01() {
334        double load1 = load.getLoad1();
335        if (Double.isNaN(load1)) {
336            // empty string if load statistics is disabled
337            return "";
338        } else {
339            return String.format("%.2f", load1);
340        }
341    }
342
343    @Override
344    public String getLoad05() {
345        double load5 = load.getLoad5();
346        if (Double.isNaN(load5)) {
347            // empty string if load statistics is disabled
348            return "";
349        } else {
350            return String.format("%.2f", load5);
351        }
352    }
353
354    @Override
355    public String getLoad15() {
356        double load15 = load.getLoad15();
357        if (Double.isNaN(load15)) {
358            // empty string if load statistics is disabled
359            return "";
360        } else {
361            return String.format("%.2f", load15);
362        }
363    }
364
365    @Override
366    public String getThroughput() {
367        double d = thp.getThroughput();
368        if (Double.isNaN(d)) {
369            // empty string if load statistics is disabled
370            return "";
371        } else {
372            return String.format("%.2f", d);
373        }
374    }
375
376    @Override
377    public long getRemoteExchangesTotal() {
378        return remoteExchangesTotal.getValue();
379    }
380
381    @Override
382    public long getRemoteExchangesCompleted() {
383        return remoteExchangesCompleted.getValue();
384    }
385
386    @Override
387    public long getRemoteExchangesFailed() {
388        return remoteExchangesFailed.getValue();
389    }
390
391    @Override
392    public long getRemoteExchangesInflight() {
393        return remoteExchangesInflight.getValue();
394    }
395
396    @Override
397    public boolean isUseBreadcrumb() {
398        return context.isUseBreadcrumb();
399    }
400
401    @Override
402    public boolean isAllowUseOriginalMessage() {
403        return context.isAllowUseOriginalMessage();
404    }
405
406    @Override
407    public boolean isMessageHistory() {
408        return context.isMessageHistory() != null ? context.isMessageHistory() : false;
409    }
410
411    @Override
412    public boolean isLogMask() {
413        return context.isLogMask() != null ? context.isLogMask() : false;
414    }
415
416    @Override
417    public boolean isUseMDCLogging() {
418        return context.isUseMDCLogging();
419    }
420
421    @Override
422    public boolean isUseDataType() {
423        return context.isUseDataType();
424    }
425
426    @Override
427    public void onTimer() {
428        load.update(getInflightExchanges());
429        thp.update(getExchangesTotal());
430    }
431
432    @Override
433    public void start() throws Exception {
434        if (context.isSuspended()) {
435            context.resume();
436        } else {
437            context.start();
438        }
439    }
440
441    @Override
442    public void stop() throws Exception {
443        context.stop();
444    }
445
446    @Override
447    public void restart() throws Exception {
448        context.stop();
449        context.start();
450    }
451
452    @Override
453    public void suspend() throws Exception {
454        context.suspend();
455    }
456
457    @Override
458    public void resume() throws Exception {
459        if (context.isSuspended()) {
460            context.resume();
461        } else {
462            throw new IllegalStateException("CamelContext is not suspended");
463        }
464    }
465
466    @Override
467    public void startAllRoutes() throws Exception {
468        context.getRouteController().startAllRoutes();
469    }
470
471    @Override
472    public boolean canSendToEndpoint(String endpointUri) {
473        try {
474            Endpoint endpoint = context.getEndpoint(endpointUri);
475            if (endpoint != null) {
476                try (Producer producer = endpoint.createProducer()) {
477                    return producer != null;
478                }
479            }
480        } catch (Exception e) {
481            // ignore
482        }
483
484        return false;
485    }
486
487    @Override
488    public void sendBody(String endpointUri, Object body) throws Exception {
489        try (ProducerTemplate template = context.createProducerTemplate()) {
490            template.sendBody(endpointUri, body);
491        }
492    }
493
494    @Override
495    public void sendStringBody(String endpointUri, String body) throws Exception {
496        sendBody(endpointUri, body);
497    }
498
499    @Override
500    public void sendBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception {
501        try (ProducerTemplate template = context.createProducerTemplate()) {
502            template.sendBodyAndHeaders(endpointUri, body, headers);
503        }
504    }
505
506    @Override
507    public Object requestBody(String endpointUri, Object body) throws Exception {
508        try (ProducerTemplate template = context.createProducerTemplate()) {
509            return template.requestBody(endpointUri, body);
510        }
511    }
512
513    @Override
514    public Object requestStringBody(String endpointUri, String body) throws Exception {
515        return requestBody(endpointUri, body);
516    }
517
518    @Override
519    public Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, Object> headers) throws Exception {
520        try (ProducerTemplate template = context.createProducerTemplate()) {
521            return template.requestBodyAndHeaders(endpointUri, body, headers);
522        }
523    }
524
525    @Override
526    public String dumpRestsAsXml() throws Exception {
527        return dumpRestsAsXml(false);
528    }
529
530    @Override
531    public String dumpRestsAsXml(boolean resolvePlaceholders) throws Exception {
532        List<RestDefinition> rests = context.getCamelContextExtension().getContextPlugin(Model.class).getRestDefinitions();
533        if (rests.isEmpty()) {
534            return null;
535        }
536
537        RestsDefinition def = new RestsDefinition();
538        def.setRests(rests);
539
540        return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def, resolvePlaceholders, true);
541    }
542
543    @Override
544    public String dumpRoutesAsXml() throws Exception {
545        return dumpRoutesAsXml(false, true);
546    }
547
548    @Override
549    public String dumpRoutesAsXml(boolean resolvePlaceholders) throws Exception {
550        return dumpRoutesAsXml(resolvePlaceholders, true);
551    }
552
553    @Override
554    public String dumpRoutesAsXml(boolean resolvePlaceholders, boolean generatedIds) throws Exception {
555        List<RouteDefinition> routes = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteDefinitions();
556        if (routes.isEmpty()) {
557            return null;
558        }
559
560        // use routes definition to dump the routes
561        RoutesDefinition def = new RoutesDefinition();
562        def.setRoutes(routes);
563
564        // if we are debugging then ids is needed for the debugger
565        if (context.isDebugging()) {
566            generatedIds = true;
567        }
568        return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def, resolvePlaceholders, generatedIds);
569    }
570
571    @Override
572    public String dumpRoutesAsYaml() throws Exception {
573        return dumpRoutesAsYaml(false, false);
574    }
575
576    @Override
577    public String dumpRoutesAsYaml(boolean resolvePlaceholders) throws Exception {
578        return dumpRoutesAsYaml(resolvePlaceholders, false, true);
579    }
580
581    @Override
582    public String dumpRoutesAsYaml(boolean resolvePlaceholders, boolean uriAsParameters) throws Exception {
583        return dumpRoutesAsYaml(resolvePlaceholders, uriAsParameters, true);
584    }
585
586    @Override
587    public String dumpRoutesAsYaml(boolean resolvePlaceholders, boolean uriAsParameters, boolean generatedIds)
588            throws Exception {
589        List<RouteDefinition> routes = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteDefinitions();
590        if (routes.isEmpty()) {
591            return null;
592        }
593
594        // use routes definition to dump the routes
595        RoutesDefinition def = new RoutesDefinition();
596        def.setRoutes(routes);
597
598        // if we are debugging then ids is needed for the debugger
599        if (context.isDebugging()) {
600            generatedIds = true;
601        }
602
603        return PluginHelper.getModelToYAMLDumper(context).dumpModelAsYaml(context, def, resolvePlaceholders, uriAsParameters,
604                generatedIds);
605    }
606
607    @Override
608    public String dumpRouteTemplatesAsXml() throws Exception {
609        List<RouteTemplateDefinition> templates
610                = context.getCamelContextExtension().getContextPlugin(Model.class).getRouteTemplateDefinitions();
611        if (templates.isEmpty()) {
612            return null;
613        }
614
615        // use a route templates definition to dump the templates
616        RouteTemplatesDefinition def = new RouteTemplatesDefinition();
617        def.setRouteTemplates(templates);
618
619        return PluginHelper.getModelToXMLDumper(context).dumpModelAsXml(context, def);
620    }
621
622    @Override
623    public String dumpRoutesStatsAsXml(boolean fullStats, boolean includeProcessors) throws Exception {
624        StringBuilder sb = new StringBuilder();
625        sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState()));
626        // use substring as we only want the attributes
627        String stat = dumpStatsAsXml(fullStats);
628        sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\"");
629        sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n");
630
631        MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer();
632        if (server != null) {
633            // gather all the routes for this CamelContext, which requires JMX
634            String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : "";
635            ObjectName query = ObjectName
636                    .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*");
637            Set<ObjectName> routes = server.queryNames(query, null);
638
639            List<ManagedProcessorMBean> processors = new ArrayList<>();
640            if (includeProcessors) {
641                // gather all the processors for this CamelContext, which requires JMX
642                query = ObjectName.getInstance(
643                        jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=processors,*");
644                Set<ObjectName> names = server.queryNames(query, null);
645                for (ObjectName on : names) {
646                    ManagedProcessorMBean processor = context.getManagementStrategy().getManagementAgent().newProxyClient(on,
647                            ManagedProcessorMBean.class);
648                    processors.add(processor);
649                }
650            }
651            processors.sort(new OrderProcessorMBeans());
652
653            // loop the routes, and append the processor stats if needed
654            sb.append("  <routeStats>\n");
655            for (ObjectName on : routes) {
656                ManagedRouteMBean route
657                        = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class);
658                sb.append("    <routeStat")
659                        .append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState()));
660                if (route.getSourceLocation() != null) {
661                    sb.append(String.format(" sourceLocation=\"%s\"", route.getSourceLocation()));
662                }
663
664                // use substring as we only want the attributes
665                stat = route.dumpStatsAsXml(fullStats);
666                sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\"");
667                sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n");
668
669                // add processor details if needed
670                if (includeProcessors) {
671                    sb.append("      <processorStats>\n");
672                    for (ManagedProcessorMBean processor : processors) {
673                        int line = processor.getSourceLineNumber() != null ? processor.getSourceLineNumber() : -1;
674                        // the processor must belong to this route
675                        if (route.getRouteId().equals(processor.getRouteId())) {
676                            sb.append("        <processorStat")
677                                    .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"",
678                                            processor.getProcessorId(), processor.getIndex(), processor.getState(), line));
679                            // use substring as we only want the attributes
680                            stat = processor.dumpStatsAsXml(fullStats);
681                            sb.append(" exchangesInflight=\"").append(processor.getExchangesInflight()).append("\"");
682                            sb.append(" ").append(stat, 7, stat.length()).append("\n");
683                        }
684                    }
685                    sb.append("      </processorStats>\n");
686                }
687                sb.append("    </routeStat>\n");
688            }
689            sb.append("  </routeStats>\n");
690        }
691
692        sb.append("</camelContextStat>");
693        return sb.toString();
694    }
695
696    @Override
697    public String dumpStepStatsAsXml(boolean fullStats) throws Exception {
698        StringBuilder sb = new StringBuilder();
699        sb.append("<camelContextStat").append(String.format(" id=\"%s\" state=\"%s\"", getCamelId(), getState()));
700        // use substring as we only want the attributes
701        String stat = dumpStatsAsXml(fullStats);
702        sb.append(" exchangesInflight=\"").append(getInflightExchanges()).append("\"");
703        sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n");
704
705        MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer();
706        if (server != null) {
707            // gather all the routes for this CamelContext, which requires JMX
708            String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : "";
709            ObjectName query = ObjectName
710                    .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*");
711            Set<ObjectName> routes = server.queryNames(query, null);
712
713            List<ManagedProcessorMBean> steps = new ArrayList<>();
714            // gather all the steps for this CamelContext, which requires JMX
715            query = ObjectName
716                    .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=steps,*");
717            Set<ObjectName> names = server.queryNames(query, null);
718            for (ObjectName on : names) {
719                ManagedStepMBean step
720                        = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedStepMBean.class);
721                steps.add(step);
722            }
723            steps.sort(new OrderProcessorMBeans());
724
725            // loop the routes, and append the processor stats if needed
726            sb.append("  <routeStats>\n");
727            for (ObjectName on : routes) {
728                ManagedRouteMBean route
729                        = context.getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedRouteMBean.class);
730                sb.append("    <routeStat")
731                        .append(String.format(" id=\"%s\" state=\"%s\"", route.getRouteId(), route.getState()));
732                if (route.getSourceLocation() != null) {
733                    sb.append(String.format(" sourceLocation=\"%s\"", route.getSourceLocation()));
734                }
735
736                // use substring as we only want the attributes
737                stat = route.dumpStatsAsXml(fullStats);
738                sb.append(" exchangesInflight=\"").append(route.getExchangesInflight()).append("\"");
739                sb.append(" ").append(stat, 7, stat.length() - 2).append(">\n");
740
741                // add steps details if needed
742                sb.append("      <stepStats>\n");
743                for (ManagedProcessorMBean step : steps) {
744                    // the step must belong to this route
745                    if (route.getRouteId().equals(step.getRouteId())) {
746                        int line = step.getSourceLineNumber() != null ? step.getSourceLineNumber() : -1;
747                        sb.append("        <stepStat")
748                                .append(String.format(" id=\"%s\" index=\"%s\" state=\"%s\" sourceLineNumber=\"%s\"",
749                                        step.getProcessorId(), step.getIndex(), step.getState(), line));
750                        // use substring as we only want the attributes
751                        stat = step.dumpStatsAsXml(fullStats);
752                        sb.append(" exchangesInflight=\"").append(step.getExchangesInflight()).append("\"");
753                        sb.append(" ").append(stat, 7, stat.length()).append("\n");
754                    }
755                    sb.append("      </stepStats>\n");
756                }
757                sb.append("    </stepStat>\n");
758            }
759            sb.append("  </routeStats>\n");
760        }
761
762        sb.append("</camelContextStat>");
763        return sb.toString();
764    }
765
766    @Override
767    public String dumpRoutesCoverageAsXml() throws Exception {
768        StringBuilder sb = new StringBuilder();
769        sb.append("<camelContextRouteCoverage")
770                .append(String.format(" id=\"%s\" exchangesTotal=\"%s\" totalProcessingTime=\"%s\"", getCamelId(),
771                        getExchangesTotal(), getTotalProcessingTime()))
772                .append(">\n");
773
774        String xml = dumpRoutesAsXml(false, true);
775        if (xml != null) {
776            // use the coverage xml parser to dump the routes and enrich with coverage stats
777            Document dom = RouteCoverageXmlParser.parseXml(context, new ByteArrayInputStream(xml.getBytes()));
778            // convert dom back to xml
779            String converted = context.getTypeConverter().convertTo(String.class, dom);
780            sb.append(converted);
781        }
782
783        sb.append("\n</camelContextRouteCoverage>");
784        return sb.toString();
785    }
786
787    @Override
788    public boolean createEndpoint(String uri) throws Exception {
789        if (context.hasEndpoint(uri) != null) {
790            // endpoint already exists
791            return false;
792        }
793
794        Endpoint endpoint = context.getEndpoint(uri);
795        if (endpoint != null) {
796            // ensure endpoint is registered, as the management strategy could have been configured to not always
797            // register new endpoints in JMX, so we need to check if its registered, and if not register it manually
798            ObjectName on
799                    = context.getManagementStrategy().getManagementObjectNameStrategy().getObjectNameForEndpoint(endpoint);
800            if (on != null && !context.getManagementStrategy().getManagementAgent().isRegistered(on)) {
801                // register endpoint as mbean
802                Object me = context.getManagementStrategy().getManagementObjectStrategy().getManagedObjectForEndpoint(context,
803                        endpoint);
804                context.getManagementStrategy().getManagementAgent().register(me, on);
805            }
806            return true;
807        } else {
808            return false;
809        }
810    }
811
812    @Override
813    public int removeEndpoints(String pattern) throws Exception {
814        // endpoints is always removed from JMX if removed from context
815        Collection<Endpoint> removed = context.removeEndpoints(pattern);
816        return removed.size();
817    }
818
819    @Override
820    public void reset(boolean includeRoutes) throws Exception {
821        reset();
822        load.reset();
823        thp.reset();
824
825        // and now reset all routes for this route
826        if (includeRoutes) {
827            MBeanServer server = getContext().getManagementStrategy().getManagementAgent().getMBeanServer();
828            if (server != null) {
829                String prefix = getContext().getManagementStrategy().getManagementAgent().getIncludeHostName() ? "*/" : "";
830                ObjectName query = ObjectName
831                        .getInstance(jmxDomain + ":context=" + prefix + getContext().getManagementName() + ",type=routes,*");
832                Set<ObjectName> names = server.queryNames(query, null);
833                for (ObjectName name : names) {
834                    server.invoke(name, "reset", new Object[] { true }, new String[] { "boolean" });
835                }
836            }
837        }
838    }
839
840    @Override
841    public Set<String> componentNames() throws Exception {
842        return context.getComponentNames();
843    }
844
845    @Override
846    public Set<String> languageNames() throws Exception {
847        return context.getLanguageNames();
848    }
849
850    @Override
851    public Set<String> dataFormatNames() throws Exception {
852        return context.getDataFormatNames();
853    }
854
855    /**
856     * Used for sorting the processor mbeans accordingly to their index.
857     */
858    private static final class OrderProcessorMBeans implements Comparator<ManagedProcessorMBean> {
859
860        @Override
861        public int compare(ManagedProcessorMBean o1, ManagedProcessorMBean o2) {
862            return o1.getIndex().compareTo(o2.getIndex());
863        }
864    }
865
866}