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