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