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