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;
018
019import java.io.IOException;
020import java.lang.management.ManagementFactory;
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.rmi.NoSuchObjectException;
024import java.rmi.RemoteException;
025import java.rmi.registry.LocateRegistry;
026import java.rmi.registry.Registry;
027import java.rmi.server.UnicastRemoteObject;
028import java.util.LinkedHashMap;
029import java.util.List;
030import java.util.Map;
031import java.util.concurrent.ConcurrentHashMap;
032import java.util.concurrent.ConcurrentMap;
033
034import javax.management.JMException;
035import javax.management.MBeanServer;
036import javax.management.MBeanServerFactory;
037import javax.management.MBeanServerInvocationHandler;
038import javax.management.NotCompliantMBeanException;
039import javax.management.ObjectInstance;
040import javax.management.ObjectName;
041import javax.management.remote.JMXConnectorServer;
042import javax.management.remote.JMXConnectorServerFactory;
043import javax.management.remote.JMXServiceURL;
044
045import org.apache.camel.CamelContext;
046import org.apache.camel.CamelContextAware;
047import org.apache.camel.ExtendedCamelContext;
048import org.apache.camel.ManagementStatisticsLevel;
049import org.apache.camel.api.management.JmxSystemPropertyKeys;
050import org.apache.camel.spi.ManagementAgent;
051import org.apache.camel.spi.ManagementMBeanAssembler;
052import org.apache.camel.support.management.DefaultManagementMBeanAssembler;
053import org.apache.camel.support.service.ServiceHelper;
054import org.apache.camel.support.service.ServiceSupport;
055import org.apache.camel.util.InetAddressUtil;
056import org.apache.camel.util.ObjectHelper;
057import org.apache.camel.util.StringHelper;
058import org.slf4j.Logger;
059import org.slf4j.LoggerFactory;
060
061/**
062 * Default implementation of the Camel JMX service agent
063 */
064public class DefaultManagementAgent extends ServiceSupport implements ManagementAgent, CamelContextAware {
065
066    public static final String DEFAULT_DOMAIN = "org.apache.camel";
067    public static final String DEFAULT_HOST = "localhost";
068    public static final int DEFAULT_REGISTRY_PORT = 1099;
069    public static final int DEFAULT_CONNECTION_PORT = -1;
070    public static final String DEFAULT_SERVICE_URL_PATH = "/jmxrmi/camel";
071    private static final Logger LOG = LoggerFactory.getLogger(DefaultManagementAgent.class);
072
073    private CamelContext camelContext;
074    private MBeanServer server;
075    private ManagementMBeanAssembler assembler;
076
077    // need a name -> actual name mapping as some servers changes the names (such as WebSphere)
078    private final ConcurrentMap<ObjectName, ObjectName> mbeansRegistered = new ConcurrentHashMap<>();
079    private JMXConnectorServer cs;
080    private Registry registry;
081
082    private Integer registryPort = DEFAULT_REGISTRY_PORT;
083    private Integer connectorPort = DEFAULT_CONNECTION_PORT;
084    private String mBeanServerDefaultDomain = DEFAULT_DOMAIN;
085    private String mBeanObjectDomainName = DEFAULT_DOMAIN;
086    private String serviceUrlPath = DEFAULT_SERVICE_URL_PATH;
087    private Boolean usePlatformMBeanServer = true;
088    private Boolean createConnector = false;
089    private Boolean onlyRegisterProcessorWithCustomId = false;
090    private Boolean loadStatisticsEnabled = false;
091    private Boolean endpointRuntimeStatisticsEnabled;
092    private Boolean registerAlways = false;
093    private Boolean registerNewRoutes = true;
094    private Boolean mask = true;
095    private Boolean includeHostName = false;
096    private Boolean useHostIPAddress = false;
097    private String managementNamePattern = "#name#";
098    private ManagementStatisticsLevel statisticsLevel = ManagementStatisticsLevel.Default;
099
100    public DefaultManagementAgent() {
101    }
102
103    public DefaultManagementAgent(CamelContext camelContext) {
104        this.camelContext = camelContext;
105    }
106
107    protected void finalizeSettings() throws Exception {
108        // JVM system properties take precedence over any configuration
109        Map<String, Object> values = new LinkedHashMap<>();
110
111        if (System.getProperty(JmxSystemPropertyKeys.REGISTRY_PORT) != null) {
112            registryPort = Integer.getInteger(JmxSystemPropertyKeys.REGISTRY_PORT);
113            values.put(JmxSystemPropertyKeys.REGISTRY_PORT, registryPort);
114        }
115        if (System.getProperty(JmxSystemPropertyKeys.CONNECTOR_PORT) != null) {
116            connectorPort = Integer.getInteger(JmxSystemPropertyKeys.CONNECTOR_PORT);
117            values.put(JmxSystemPropertyKeys.CONNECTOR_PORT, connectorPort);
118        }
119        if (System.getProperty(JmxSystemPropertyKeys.DOMAIN) != null) {
120            mBeanServerDefaultDomain = System.getProperty(JmxSystemPropertyKeys.DOMAIN);
121            values.put(JmxSystemPropertyKeys.DOMAIN, mBeanServerDefaultDomain);
122        }
123        if (System.getProperty(JmxSystemPropertyKeys.MBEAN_DOMAIN) != null) {
124            mBeanObjectDomainName = System.getProperty(JmxSystemPropertyKeys.MBEAN_DOMAIN);
125            values.put(JmxSystemPropertyKeys.MBEAN_DOMAIN, mBeanObjectDomainName);
126        }
127        if (System.getProperty(JmxSystemPropertyKeys.SERVICE_URL_PATH) != null) {
128            serviceUrlPath = System.getProperty(JmxSystemPropertyKeys.SERVICE_URL_PATH);
129            values.put(JmxSystemPropertyKeys.SERVICE_URL_PATH, serviceUrlPath);
130        }
131        if (System.getProperty(JmxSystemPropertyKeys.CREATE_CONNECTOR) != null) {
132            createConnector = Boolean.getBoolean(JmxSystemPropertyKeys.CREATE_CONNECTOR);
133            values.put(JmxSystemPropertyKeys.CREATE_CONNECTOR, createConnector);
134        }
135        if (System.getProperty(JmxSystemPropertyKeys.ONLY_REGISTER_PROCESSOR_WITH_CUSTOM_ID) != null) {
136            onlyRegisterProcessorWithCustomId = Boolean.getBoolean(JmxSystemPropertyKeys.ONLY_REGISTER_PROCESSOR_WITH_CUSTOM_ID);
137            values.put(JmxSystemPropertyKeys.ONLY_REGISTER_PROCESSOR_WITH_CUSTOM_ID, onlyRegisterProcessorWithCustomId);
138        }
139        if (System.getProperty(JmxSystemPropertyKeys.USE_PLATFORM_MBS) != null) {
140            usePlatformMBeanServer = Boolean.getBoolean(JmxSystemPropertyKeys.USE_PLATFORM_MBS);
141            values.put(JmxSystemPropertyKeys.USE_PLATFORM_MBS, usePlatformMBeanServer);
142        }
143        if (System.getProperty(JmxSystemPropertyKeys.REGISTER_ALWAYS) != null) {
144            registerAlways = Boolean.getBoolean(JmxSystemPropertyKeys.REGISTER_ALWAYS);
145            values.put(JmxSystemPropertyKeys.REGISTER_ALWAYS, registerAlways);
146        }
147        if (System.getProperty(JmxSystemPropertyKeys.REGISTER_NEW_ROUTES) != null) {
148            registerNewRoutes = Boolean.getBoolean(JmxSystemPropertyKeys.REGISTER_NEW_ROUTES);
149            values.put(JmxSystemPropertyKeys.REGISTER_NEW_ROUTES, registerNewRoutes);
150        }
151        if (System.getProperty(JmxSystemPropertyKeys.MASK) != null) {
152            mask = Boolean.getBoolean(JmxSystemPropertyKeys.MASK);
153            values.put(JmxSystemPropertyKeys.MASK, mask);
154        }
155        if (System.getProperty(JmxSystemPropertyKeys.INCLUDE_HOST_NAME) != null) {
156            includeHostName = Boolean.getBoolean(JmxSystemPropertyKeys.INCLUDE_HOST_NAME);
157            values.put(JmxSystemPropertyKeys.INCLUDE_HOST_NAME, includeHostName);
158        }
159        if (System.getProperty(JmxSystemPropertyKeys.CREATE_CONNECTOR) != null) {
160            createConnector = Boolean.getBoolean(JmxSystemPropertyKeys.CREATE_CONNECTOR);
161            values.put(JmxSystemPropertyKeys.CREATE_CONNECTOR, createConnector);
162        }
163        if (System.getProperty(JmxSystemPropertyKeys.LOAD_STATISTICS_ENABLED) != null) {
164            loadStatisticsEnabled = Boolean.getBoolean(JmxSystemPropertyKeys.LOAD_STATISTICS_ENABLED);
165            values.put(JmxSystemPropertyKeys.LOAD_STATISTICS_ENABLED, loadStatisticsEnabled);
166        }
167        if (System.getProperty(JmxSystemPropertyKeys.ENDPOINT_RUNTIME_STATISTICS_ENABLED) != null) {
168            endpointRuntimeStatisticsEnabled = Boolean.getBoolean(JmxSystemPropertyKeys.ENDPOINT_RUNTIME_STATISTICS_ENABLED);
169            values.put(JmxSystemPropertyKeys.ENDPOINT_RUNTIME_STATISTICS_ENABLED, endpointRuntimeStatisticsEnabled);
170        }
171        if (System.getProperty(JmxSystemPropertyKeys.STATISTICS_LEVEL) != null) {
172            statisticsLevel = camelContext.getTypeConverter().mandatoryConvertTo(ManagementStatisticsLevel.class, System.getProperty(JmxSystemPropertyKeys.STATISTICS_LEVEL));
173            values.put(JmxSystemPropertyKeys.STATISTICS_LEVEL, statisticsLevel);
174        }
175        if (System.getProperty(JmxSystemPropertyKeys.MANAGEMENT_NAME_PATTERN) != null) {
176            managementNamePattern = System.getProperty(JmxSystemPropertyKeys.MANAGEMENT_NAME_PATTERN);
177            values.put(JmxSystemPropertyKeys.MANAGEMENT_NAME_PATTERN, managementNamePattern);
178        }
179        if (System.getProperty(JmxSystemPropertyKeys.USE_HOST_IP_ADDRESS) != null) {
180            useHostIPAddress = Boolean.getBoolean(JmxSystemPropertyKeys.USE_HOST_IP_ADDRESS);
181            values.put(JmxSystemPropertyKeys.USE_HOST_IP_ADDRESS, useHostIPAddress);
182        }
183
184        if (!values.isEmpty()) {
185            LOG.info("ManagementAgent detected JVM system properties: {}", values);
186        }
187    }
188
189    @Override
190    public void setRegistryPort(Integer port) {
191        registryPort = port;
192    }
193
194    @Override
195    public Integer getRegistryPort() {
196        return registryPort;
197    }
198
199    @Override
200    public void setConnectorPort(Integer port) {
201        connectorPort = port;
202    }
203
204    @Override
205    public Integer getConnectorPort() {
206        return connectorPort;
207    }
208
209    @Override
210    public void setMBeanServerDefaultDomain(String domain) {
211        mBeanServerDefaultDomain = domain;
212    }
213
214    @Override
215    public String getMBeanServerDefaultDomain() {
216        return mBeanServerDefaultDomain;
217    }
218
219    @Override
220    public void setMBeanObjectDomainName(String domainName) {
221        mBeanObjectDomainName = domainName;
222    }
223
224    @Override
225    public String getMBeanObjectDomainName() {
226        return mBeanObjectDomainName;
227    }
228
229    @Override
230    public void setServiceUrlPath(String url) {
231        serviceUrlPath = url;
232    }
233
234    @Override
235    public String getServiceUrlPath() {
236        return serviceUrlPath;
237    }
238
239    @Override
240    public void setCreateConnector(Boolean flag) {
241        createConnector = flag;
242    }
243
244    @Override
245    public Boolean getCreateConnector() {
246        return createConnector;
247    }
248
249    @Override
250    public void setUsePlatformMBeanServer(Boolean flag) {
251        usePlatformMBeanServer = flag;
252    }
253
254    @Override
255    public Boolean getUsePlatformMBeanServer() {
256        return usePlatformMBeanServer;
257    }
258
259    @Override
260    public Boolean getOnlyRegisterProcessorWithCustomId() {
261        return onlyRegisterProcessorWithCustomId;
262    }
263
264    @Override
265    public void setOnlyRegisterProcessorWithCustomId(Boolean onlyRegisterProcessorWithCustomId) {
266        this.onlyRegisterProcessorWithCustomId = onlyRegisterProcessorWithCustomId;
267    }
268
269    @Override
270    public void setMBeanServer(MBeanServer mbeanServer) {
271        server = mbeanServer;
272    }
273
274    @Override
275    public MBeanServer getMBeanServer() {
276        return server;
277    }
278
279    @Override
280    public Boolean getRegisterAlways() {
281        return registerAlways != null && registerAlways;
282    }
283
284    @Override
285    public void setRegisterAlways(Boolean registerAlways) {
286        this.registerAlways = registerAlways;
287    }
288
289    @Override
290    public Boolean getRegisterNewRoutes() {
291        return registerNewRoutes != null && registerNewRoutes;
292    }
293
294    @Override
295    public void setRegisterNewRoutes(Boolean registerNewRoutes) {
296        this.registerNewRoutes = registerNewRoutes;
297    }
298
299    @Override
300    public Boolean getMask() {
301        return mask != null && mask;
302    }
303
304    @Override
305    public void setMask(Boolean mask) {
306        this.mask = mask;
307    }
308
309    @Override
310    public Boolean getIncludeHostName() {
311        return includeHostName != null && includeHostName;
312    }
313
314    @Override
315    public void setIncludeHostName(Boolean includeHostName) {
316        this.includeHostName = includeHostName;
317    }
318
319    @Override
320    public Boolean getUseHostIPAddress() {
321        return useHostIPAddress != null && useHostIPAddress;
322    }
323
324    @Override
325    public void setUseHostIPAddress(Boolean useHostIPAddress) {
326        this.useHostIPAddress = useHostIPAddress;
327    }
328
329    @Override
330    public String getManagementNamePattern() {
331        return managementNamePattern;
332    }
333
334    @Override
335    public void setManagementNamePattern(String managementNamePattern) {
336        this.managementNamePattern = managementNamePattern;
337    }
338
339    @Override
340    public Boolean getLoadStatisticsEnabled() {
341        return loadStatisticsEnabled;
342    }
343
344    @Override
345    public void setLoadStatisticsEnabled(Boolean loadStatisticsEnabled) {
346        this.loadStatisticsEnabled = loadStatisticsEnabled;
347    }
348
349    @Override
350    public Boolean getEndpointRuntimeStatisticsEnabled() {
351        return endpointRuntimeStatisticsEnabled;
352    }
353
354    @Override
355    public void setEndpointRuntimeStatisticsEnabled(Boolean endpointRuntimeStatisticsEnabled) {
356        this.endpointRuntimeStatisticsEnabled = endpointRuntimeStatisticsEnabled;
357    }
358
359    @Override
360    public ManagementStatisticsLevel getStatisticsLevel() {
361        return statisticsLevel;
362    }
363
364    @Override
365    public void setStatisticsLevel(ManagementStatisticsLevel statisticsLevel) {
366        this.statisticsLevel = statisticsLevel;
367    }
368
369    @Override
370    public CamelContext getCamelContext() {
371        return camelContext;
372    }
373
374    @Override
375    public void setCamelContext(CamelContext camelContext) {
376        this.camelContext = camelContext;
377    }
378
379    @Override
380    public void register(Object obj, ObjectName name) throws JMException {
381        register(obj, name, false);
382    }
383
384    @Override
385    public void register(Object obj, ObjectName name, boolean forceRegistration) throws JMException {
386        try {
387            registerMBeanWithServer(obj, name, forceRegistration);
388        } catch (NotCompliantMBeanException e) {
389            // If this is not a "normal" MBean, then try to deploy it using JMX annotations
390            ObjectHelper.notNull(assembler, "ManagementMBeanAssembler", camelContext);
391            Object mbean = assembler.assemble(server, obj, name);
392            if (mbean != null) {
393                // and register the mbean
394                registerMBeanWithServer(mbean, name, forceRegistration);
395            }
396        }
397    }
398
399    @Override
400    public void unregister(ObjectName name) throws JMException {
401        if (isRegistered(name)) {
402            ObjectName on = mbeansRegistered.remove(name);
403            server.unregisterMBean(on);
404            LOG.debug("Unregistered MBean with ObjectName: {}", name);
405        } else {
406            mbeansRegistered.remove(name);
407        }
408    }
409
410    @Override
411    public boolean isRegistered(ObjectName name) {
412        if (server == null) {
413            return false;
414        }
415        ObjectName on = mbeansRegistered.get(name);
416        return (on != null && server.isRegistered(on))
417                || server.isRegistered(name);
418    }
419
420    @Override
421    public <T> T newProxyClient(ObjectName name, Class<T> mbean) {
422        if (isRegistered(name)) {
423            ObjectName on = mbeansRegistered.get(name);
424            return MBeanServerInvocationHandler.newProxyInstance(server, on != null ? on : name, mbean, false);
425        } else {
426            return null;
427        }
428    }
429
430    @Override
431    protected void doStart() throws Exception {
432        ObjectHelper.notNull(camelContext, "CamelContext");
433
434        // create mbean server if is has not be injected.
435        if (server == null) {
436            finalizeSettings();
437            createMBeanServer();
438        }
439
440        // ensure assembler is started
441        assembler = camelContext.adapt(ExtendedCamelContext.class).getManagementMBeanAssembler();
442        if (assembler == null) {
443            assembler = new DefaultManagementMBeanAssembler(camelContext);
444        }
445        ServiceHelper.startService(assembler);
446
447        LOG.debug("Starting JMX agent on server: {}", getMBeanServer());
448    }
449
450    @Override
451    protected void doStop() throws Exception {
452        // close JMX Connector, if it was created
453        if (cs != null) {
454            try {
455                cs.stop();
456                LOG.debug("Stopped JMX Connector");
457            } catch (IOException e) {
458                LOG.debug("Error occurred during stopping JMXConnectorService: "
459                        + cs + ". This exception will be ignored.");
460            }
461            cs = null;
462        }
463
464        // Unexport JMX RMI registry, if it was created
465        if (registry != null) {
466            try {
467                UnicastRemoteObject.unexportObject(registry, true);
468                LOG.debug("Unexported JMX RMI Registry");
469            } catch (NoSuchObjectException e) {
470                LOG.debug("Error occurred while unexporting JMX RMI registry. This exception will be ignored.");
471            }
472        }
473
474        if (mbeansRegistered.isEmpty()) {
475            return;
476        }
477
478        // Using the array to hold the busMBeans to avoid the CurrentModificationException
479        ObjectName[] mBeans = mbeansRegistered.keySet().toArray(new ObjectName[mbeansRegistered.size()]);
480        int caught = 0;
481        for (ObjectName name : mBeans) {
482            try {
483                unregister(name);
484            } catch (Exception e) {
485                LOG.info("Exception unregistering MBean with name {}", name, e);
486                caught++;
487            }
488        }
489        if (caught > 0) {
490            LOG.warn("A number of " + caught
491                     + " exceptions caught while unregistering MBeans during stop operation."
492                     + " See INFO log for details.");
493        }
494
495        ServiceHelper.stopService(assembler);
496    }
497
498    private void registerMBeanWithServer(Object obj, ObjectName name, boolean forceRegistration)
499        throws JMException {
500
501        // have we already registered the bean, there can be shared instances in the camel routes
502        boolean exists = isRegistered(name);
503        if (exists) {
504            if (forceRegistration) {
505                LOG.info("ForceRegistration enabled, unregistering existing MBean with ObjectName: {}", name);
506                server.unregisterMBean(name);
507            } else {
508                // okay ignore we do not want to force it and it could be a shared instance
509                LOG.debug("MBean already registered with ObjectName: {}", name);
510            }
511        }
512
513        // register bean if by force or not exists
514        ObjectInstance instance = null;
515        if (forceRegistration || !exists) {
516            LOG.trace("Registering MBean with ObjectName: {}", name);
517            instance = server.registerMBean(obj, name);
518        }
519
520        // need to use the name returned from the server as some JEE servers may modify the name
521        if (instance != null) {
522            ObjectName registeredName = instance.getObjectName();
523            LOG.debug("Registered MBean with ObjectName: {}", registeredName);
524            mbeansRegistered.put(name, registeredName);
525        }
526    }
527
528    protected void createMBeanServer() {
529        String hostName;
530        boolean canAccessSystemProps = true;
531        try {
532            // we'll do it this way mostly to determine if we should lookup the hostName
533            SecurityManager sm = System.getSecurityManager();
534            if (sm != null) {
535                sm.checkPropertiesAccess();
536            }
537        } catch (SecurityException se) {
538            canAccessSystemProps = false;
539        }
540
541        if (canAccessSystemProps) {
542            try {
543                if (useHostIPAddress) {
544                    hostName = InetAddress.getLocalHost().getHostAddress();
545                } else {
546                    hostName = InetAddressUtil.getLocalHostName();
547                }
548            } catch (UnknownHostException uhe) {
549                LOG.info("Cannot determine localhost name or address. Using default: {}", DEFAULT_REGISTRY_PORT, uhe);
550                hostName = DEFAULT_HOST;
551            }
552        } else {
553            hostName = DEFAULT_HOST;
554        }
555
556        server = findOrCreateMBeanServer();
557
558        try {
559            // Create the connector if we need
560            if (createConnector) {
561                createJmxConnector(hostName);
562            }
563        } catch (IOException ioe) {
564            LOG.warn("Could not create and start JMX connector.", ioe);
565        }
566    }
567    
568    protected MBeanServer findOrCreateMBeanServer() {
569
570        // return platform mbean server if the option is specified.
571        if (usePlatformMBeanServer) {
572            return ManagementFactory.getPlatformMBeanServer();
573        }
574
575        // look for the first mbean server that has match default domain name
576        List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(null);
577
578        for (MBeanServer server : servers) {
579            LOG.debug("Found MBeanServer with default domain {}", server.getDefaultDomain());
580
581            if (mBeanServerDefaultDomain.equals(server.getDefaultDomain())) {
582                return server;
583            }
584        }
585
586        // create a mbean server with the given default domain name
587        return MBeanServerFactory.createMBeanServer(mBeanServerDefaultDomain);
588    }
589
590    protected void createJmxConnector(String host) throws IOException {
591        StringHelper.notEmpty(serviceUrlPath, "serviceUrlPath");
592        ObjectHelper.notNull(registryPort, "registryPort");
593
594        try {
595            registry = LocateRegistry.createRegistry(registryPort);
596            LOG.debug("Created JMXConnector RMI registry on port {}", registryPort);
597        } catch (RemoteException ex) {
598            // The registry may had been created, we could get the registry instead
599        }
600
601        // must start with leading slash
602        String path = serviceUrlPath.startsWith("/") ? serviceUrlPath : "/" + serviceUrlPath;
603        // Create an RMI connector and start it
604        final JMXServiceURL url;
605        if (connectorPort > 0) {
606            url = new JMXServiceURL("service:jmx:rmi://" + host + ":" + connectorPort + "/jndi/rmi://" + host
607                                    + ":" + registryPort + path);
608        } else {
609            url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + host + ":" + registryPort + path);
610        }
611
612        cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
613
614        // use async thread for starting the JMX Connector
615        // (no need to use a thread pool or enlist in JMX as this thread is terminated when the JMX connector has been started)
616        String threadName = camelContext.getExecutorServiceManager().resolveThreadName("JMXConnector: " + url);
617        Thread thread = getCamelContext().getExecutorServiceManager().newThread(threadName, () -> {
618            try {
619                LOG.debug("Staring JMX Connector thread to listen at: {}", url);
620                cs.start();
621                LOG.info("JMX Connector thread started and listening at: {}", url);
622            } catch (IOException ioe) {
623                LOG.warn("Could not start JMXConnector thread at: " + url + ". JMX Connector not in use.", ioe);
624            }
625        });
626        thread.start();
627    }
628
629}