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