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