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