View Javadoc

1   /*
2    * $Id: JmxAgent.java 20088 2010-11-05 16:51:41Z aperepel $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  package org.mule.module.management.agent;
11  
12  import org.mule.AbstractAgent;
13  import org.mule.api.MuleException;
14  import org.mule.api.MuleRuntimeException;
15  import org.mule.api.context.notification.MuleContextNotificationListener;
16  import org.mule.api.lifecycle.InitialisationException;
17  import org.mule.api.model.Model;
18  import org.mule.api.service.Service;
19  import org.mule.api.transport.Connector;
20  import org.mule.api.transport.MessageReceiver;
21  import org.mule.config.i18n.CoreMessages;
22  import org.mule.context.notification.MuleContextNotification;
23  import org.mule.context.notification.NotificationException;
24  import org.mule.module.management.i18n.ManagementMessages;
25  import org.mule.module.management.mbean.ConnectorService;
26  import org.mule.module.management.mbean.ConnectorServiceMBean;
27  import org.mule.module.management.mbean.EndpointService;
28  import org.mule.module.management.mbean.EndpointServiceMBean;
29  import org.mule.module.management.mbean.ModelService;
30  import org.mule.module.management.mbean.ModelServiceMBean;
31  import org.mule.module.management.mbean.MuleConfigurationService;
32  import org.mule.module.management.mbean.MuleConfigurationServiceMBean;
33  import org.mule.module.management.mbean.MuleService;
34  import org.mule.module.management.mbean.MuleServiceMBean;
35  import org.mule.module.management.mbean.ServiceService;
36  import org.mule.module.management.mbean.ServiceServiceMBean;
37  import org.mule.module.management.mbean.StatisticsService;
38  import org.mule.module.management.mbean.StatisticsServiceMBean;
39  import org.mule.module.management.support.AutoDiscoveryJmxSupportFactory;
40  import org.mule.module.management.support.JmxSupport;
41  import org.mule.module.management.support.JmxSupportFactory;
42  import org.mule.module.management.support.SimplePasswordJmxAuthenticator;
43  import org.mule.transport.AbstractConnector;
44  import org.mule.util.ClassUtils;
45  import org.mule.util.StringUtils;
46  
47  import java.lang.management.ManagementFactory;
48  import java.net.URI;
49  import java.rmi.RemoteException;
50  import java.rmi.registry.LocateRegistry;
51  import java.rmi.registry.Registry;
52  import java.rmi.server.ExportException;
53  import java.util.Collections;
54  import java.util.HashMap;
55  import java.util.Map;
56  import java.util.Set;
57  
58  import javax.management.InstanceAlreadyExistsException;
59  import javax.management.MBeanRegistrationException;
60  import javax.management.MBeanServer;
61  import javax.management.MBeanServerFactory;
62  import javax.management.MalformedObjectNameException;
63  import javax.management.NotCompliantMBeanException;
64  import javax.management.ObjectName;
65  import javax.management.remote.JMXAuthenticator;
66  import javax.management.remote.JMXConnectorServer;
67  import javax.management.remote.JMXConnectorServerFactory;
68  import javax.management.remote.JMXServiceURL;
69  import javax.management.remote.rmi.RMIConnectorServer;
70  
71  import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
72  
73  import org.apache.commons.logging.Log;
74  import org.apache.commons.logging.LogFactory;
75  
76  /**
77   * <code>JmxAgent</code> registers Mule Jmx management beans with an MBean server.
78   */
79  public class JmxAgent extends AbstractAgent
80  {
81      public static final String NAME = "jmx-agent";
82  
83      public static final String DEFAULT_REMOTING_URI = "service:jmx:rmi:///jndi/rmi://localhost:1099/server";
84      
85      // populated with values below in a static initializer
86      public static final Map<String, String> DEFAULT_CONNECTOR_SERVER_PROPERTIES;
87  
88      /**
89       * Default JMX Authenticator to use for securing remote access.
90       */
91      public static final String DEFAULT_JMX_AUTHENTICATOR = SimplePasswordJmxAuthenticator.class.getName();
92  
93      /**
94       * Logger used by this class
95       */
96      protected static final Log logger = LogFactory.getLog(JmxAgent.class);
97  
98      /**
99       * Should MBeanServer be discovered.
100      */
101     protected boolean locateServer = true;
102 
103     protected boolean containerMode = true;
104 
105     // don't create mbean server by default, use a platform mbean server
106     private boolean createServer = false;
107     private String connectorServerUrl;
108     private MBeanServer mBeanServer;
109     private JMXConnectorServer connectorServer;
110     private Map<String, Object> connectorServerProperties = null;
111     private boolean enableStatistics = true;
112     private final AtomicBoolean serverCreated = new AtomicBoolean(false);
113     private final AtomicBoolean initialized = new AtomicBoolean(false);
114 
115     private JmxSupportFactory jmxSupportFactory = AutoDiscoveryJmxSupportFactory.getInstance();
116     private JmxSupport jmxSupport = jmxSupportFactory.getJmxSupport();
117 
118     //Used is RMI is being used
119     private Registry rmiRegistry;
120     private boolean createRmiRegistry = true;
121     /**
122      * Username/password combinations for JMX Remoting authentication.
123      */
124     private Map<String, String> credentials = new HashMap<String, String>();
125 
126     static
127     {
128         Map<String, String> props = new HashMap<String, String>(1);
129         props.put(RMIConnectorServer.JNDI_REBIND_ATTRIBUTE, "true");
130         DEFAULT_CONNECTOR_SERVER_PROPERTIES = Collections.unmodifiableMap(props);
131     }
132 
133     public JmxAgent()
134     {
135         super(NAME);
136         connectorServerProperties = new HashMap<String, Object>(DEFAULT_CONNECTOR_SERVER_PROPERTIES);
137     }
138 
139     @Override
140     public String getDescription()
141     {
142         if (connectorServerUrl != null)
143         {
144             return name + ": " + connectorServerUrl;
145         }
146         else
147         {
148             return "JMX Agent";
149         }
150     }
151 
152     /**
153      * {@inheritDoc}
154      */
155     public void initialise() throws InitialisationException
156     {
157         if (initialized.get())
158         {
159             return;
160         }
161 
162         this.containerMode = muleContext.getConfiguration().isContainerMode();
163 
164         try
165         {
166             Object agent = muleContext.getRegistry().lookupObject(this.getClass());
167             // if we find ourselves, but not initialized yet - proceed with init, otherwise return
168             if (agent == this && this.initialized.get())
169             {
170                 if (logger.isDebugEnabled())
171                 {
172                     logger.debug("Found an existing JMX agent in the registry, we're done here.");
173                 }
174                 return;
175             }
176         }
177         catch (Exception e)
178         {
179             throw new InitialisationException(e, this);
180         }
181 
182 
183         if (mBeanServer == null && createServer)
184         {
185             // here we create a new mbean server, not using a platform one
186             mBeanServer = MBeanServerFactory.createMBeanServer();
187             serverCreated.set(true);
188         }
189 
190         if (mBeanServer == null && locateServer)
191         {
192             mBeanServer = ManagementFactory.getPlatformMBeanServer();
193         }
194 
195         if (mBeanServer == null)
196         {
197             throw new InitialisationException(ManagementMessages.cannotLocateOrCreateServer(), this);
198         }
199 
200         if (StringUtils.isBlank(muleContext.getConfiguration().getId()))
201         {
202             // TODO i18n the message properly
203             throw new IllegalArgumentException(
204                     "Manager ID is mandatory when running with JmxAgent. Give your Mule configuration a valid ID.");
205         }
206 
207         try
208         {
209             // We need to register all the services once the server has initialised
210             muleContext.registerListener(new MuleContextStartedListener());
211             // and unregister once context stopped
212             muleContext.registerListener(new MuleContextStoppedListener());
213         }
214         catch (NotificationException e)
215         {
216             throw new InitialisationException(e, this);
217         }
218         initialized.compareAndSet(false, true);
219     }
220 
221     protected void initRMI() throws Exception
222     {
223         String connectUri = (connectorServerUrl != null ? connectorServerUrl : DEFAULT_REMOTING_URI);
224         if (connectUri.contains("jmx:rmi"))
225         {
226             int i = connectUri.lastIndexOf("rmi://");
227             URI uri = new URI(connectUri.substring(i));
228             if (rmiRegistry == null)
229             {
230                 try
231                 {
232                     if (isCreateRmiRegistry())
233                     {
234                         try
235                         {
236                             rmiRegistry = LocateRegistry.createRegistry(uri.getPort());
237                         }
238                         catch (ExportException e)
239                         {
240                             logger.info("Registry on " + uri  + " already bound. Attempting to use that instead");
241                             rmiRegistry = LocateRegistry.getRegistry(uri.getHost(), uri.getPort());
242                         }
243                     }
244                     else
245                     {
246                         rmiRegistry = LocateRegistry.getRegistry(uri.getHost(), uri.getPort());
247                     }
248                 }
249                 catch (RemoteException e)
250                 {
251                     throw new InitialisationException(e, this);
252                 }
253             }
254         }
255     }
256 
257     public void start() throws MuleException
258     {
259         try
260         {
261             // TODO cleanup rmi registry creation too
262             initRMI();
263             if (connectorServerUrl == null)
264             {
265                 return;
266             }
267 
268             logger.info("Creating and starting JMX agent connector Server");
269             JMXServiceURL url = new JMXServiceURL(connectorServerUrl);
270             if (connectorServerProperties == null)
271             {
272                 connectorServerProperties = new HashMap<String, Object>(DEFAULT_CONNECTOR_SERVER_PROPERTIES);
273             }
274             // TODO custom authenticator may have its own security config,
275             // refactor
276             if (!credentials.isEmpty())
277             {
278                 JMXAuthenticator jmxAuthenticator = (JMXAuthenticator) ClassUtils.instanciateClass(DEFAULT_JMX_AUTHENTICATOR);
279                 // TODO support for custom authenticators
280                 ((SimplePasswordJmxAuthenticator) jmxAuthenticator).setCredentials(credentials);
281                 connectorServerProperties.put(JMXConnectorServer.AUTHENTICATOR, jmxAuthenticator);
282             }
283             connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url,
284                                                                               connectorServerProperties,
285                                                                               mBeanServer);
286             connectorServer.start();
287         }
288         catch (ExportException e)
289         {
290             throw new JmxManagementException(CoreMessages.failedToStart("Jmx Agent"), e);
291         }
292         catch (Exception e)
293         {
294             throw new JmxManagementException(CoreMessages.failedToStart("Jmx Agent"), e);
295         }
296     }
297 
298     public void stop() throws MuleException
299     {
300         if (connectorServer != null)
301         {
302             try
303             {
304                 connectorServer.stop();
305             }
306             catch (Exception e)
307             {
308                 throw new JmxManagementException(CoreMessages.failedToStop("Jmx Connector"), e);
309             }
310         }
311     }
312 
313     /**
314      * {@inheritDoc}
315      */
316     public void dispose()
317     {
318         unregisterMBeansIfNecessary();
319         if (serverCreated.get())
320         {
321             MBeanServerFactory.releaseMBeanServer(mBeanServer);
322         }
323         mBeanServer = null;
324         serverCreated.compareAndSet(true, false);
325         initialized.set(false);
326     }
327 
328     /**
329      * Register a Java Service Wrapper agent.
330      *
331      * @throws MuleException if registration failed
332      */
333     protected void registerWrapperService() throws MuleException
334     {
335         // WrapperManager to support restarts
336         final WrapperManagerAgent wmAgent = new WrapperManagerAgent();
337         if (muleContext.getRegistry().lookupAgent(wmAgent.getName()) == null)
338         {
339             muleContext.getRegistry().registerAgent(wmAgent);
340         }
341     }
342 
343     protected void registerStatisticsService() throws NotCompliantMBeanException, MBeanRegistrationException,
344         InstanceAlreadyExistsException, MalformedObjectNameException
345     {
346         ObjectName on = jmxSupport.getObjectName(String.format("%s:%s", jmxSupport.getDomainName(muleContext, !containerMode), StatisticsServiceMBean.DEFAULT_JMX_NAME));
347         StatisticsService service = new StatisticsService();
348         service.setMuleContext(muleContext);
349         service.setEnabled(isEnableStatistics());
350         ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(service, StatisticsServiceMBean.class, muleContext.getExecutionClassLoader());
351         logger.debug("Registering statistics with name: " + on);
352         mBeanServer.registerMBean(mBean, on);
353     }
354 
355     protected void registerModelServices() throws NotCompliantMBeanException, MBeanRegistrationException,
356             InstanceAlreadyExistsException, MalformedObjectNameException
357     {
358         for (Model model : muleContext.getRegistry().lookupObjects(Model.class))
359         {
360             ModelServiceMBean service = new ModelService(model);
361             String rawName = service.getName() + "(" + service.getType() + ")";
362             String name = jmxSupport.escape(rawName);
363             final String jmxName = String.format("%s:%s%s", jmxSupport.getDomainName(muleContext, !containerMode), ModelServiceMBean.DEFAULT_JMX_NAME_PREFIX, name);
364             ObjectName on = jmxSupport.getObjectName(jmxName);
365             ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(service, ModelServiceMBean.class, muleContext.getExecutionClassLoader());
366             logger.debug("Registering model with name: " + on);
367             mBeanServer.registerMBean(mBean, on);
368         }
369     }
370 
371     protected void registerMuleService() throws NotCompliantMBeanException, MBeanRegistrationException,
372         InstanceAlreadyExistsException, MalformedObjectNameException
373     {
374         ObjectName on = jmxSupport.getObjectName(String.format("%s:%s", jmxSupport.getDomainName(muleContext, !containerMode), MuleServiceMBean.DEFAULT_JMX_NAME));
375         if (muleContext.getConfiguration().isContainerMode() && mBeanServer.isRegistered(on))
376         {
377             // while in container mode, a previous stop() action leaves MuleContext MBean behind for remote start() operation
378             return;
379         }
380         MuleService service = new MuleService(muleContext);
381         ClassloaderSwitchingMBeanWrapper serviceMBean = new ClassloaderSwitchingMBeanWrapper(service, MuleServiceMBean.class, muleContext.getExecutionClassLoader());
382         logger.debug("Registering mule with name: " + on);
383         mBeanServer.registerMBean(serviceMBean, on);
384     }
385 
386     protected void registerConfigurationService() throws NotCompliantMBeanException, MBeanRegistrationException,
387             InstanceAlreadyExistsException, MalformedObjectNameException
388     {
389         ObjectName on = jmxSupport.getObjectName(String.format("%s:%s", jmxSupport.getDomainName(muleContext, !containerMode), MuleConfigurationServiceMBean.DEFAULT_JMX_NAME));
390         MuleConfigurationServiceMBean service = new MuleConfigurationService(muleContext.getConfiguration());
391         ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(service, MuleConfigurationServiceMBean.class, muleContext.getExecutionClassLoader());
392         logger.debug("Registering configuration with name: " + on);
393         mBeanServer.registerMBean(mBean, on);
394     }
395 
396     protected void registerServiceServices() throws NotCompliantMBeanException, MBeanRegistrationException,
397         InstanceAlreadyExistsException, MalformedObjectNameException
398     {
399         for (Service service : muleContext.getRegistry().lookupObjects(Service.class))
400         {
401             final String rawName = service.getName();
402             final String name = jmxSupport.escape(rawName);
403             final String jmxName = String.format("%s:%s%s", jmxSupport.getDomainName(muleContext, !containerMode), ServiceServiceMBean.DEFAULT_JMX_NAME_PREFIX, name);
404             ObjectName on = jmxSupport.getObjectName(jmxName);
405             ServiceServiceMBean serviceMBean = new ServiceService(rawName, muleContext);
406             ClassloaderSwitchingMBeanWrapper wrapper = new ClassloaderSwitchingMBeanWrapper(serviceMBean, ServiceServiceMBean.class, muleContext.getExecutionClassLoader());
407             logger.debug("Registering service with name: " + on);
408             mBeanServer.registerMBean(wrapper, on);
409         }
410     }
411 
412     protected void registerEndpointServices() throws NotCompliantMBeanException, MBeanRegistrationException,
413         InstanceAlreadyExistsException, MalformedObjectNameException
414     {
415         for (Connector connector : muleContext.getRegistry().lookupObjects(Connector.class))
416         {
417             if (connector instanceof AbstractConnector)
418             {
419                 for (MessageReceiver messageReceiver : ((AbstractConnector) connector).getReceivers().values())
420                 {
421                     EndpointServiceMBean service = new EndpointService(messageReceiver);
422 
423                     String fullName = buildFullyQualifiedEndpointName(service, connector);
424                     if (logger.isInfoEnabled())
425                     {
426                         logger.info("Attempting to register service with name: " + fullName);
427                     }
428 
429                     ObjectName on = jmxSupport.getObjectName(fullName);
430                     ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(service, EndpointServiceMBean.class, muleContext.getExecutionClassLoader());
431                     mBeanServer.registerMBean(mBean, on);
432                     if (logger.isInfoEnabled())
433                     {
434                         logger.info("Registered Endpoint Service with name: " + on);
435                     }
436                 }
437             }
438             else
439             {
440                 logger.warn("Connector: " + connector
441                         + " is not an istance of AbstractConnector, cannot obtain Endpoint MBeans from it");
442             }
443         }
444     }
445 
446     protected String buildFullyQualifiedEndpointName(EndpointServiceMBean mBean, Connector connector)
447     {
448         String rawName = jmxSupport.escape(mBean.getName());
449 
450         StringBuilder fullName = new StringBuilder(128);
451         fullName.append(jmxSupport.getDomainName(muleContext, !containerMode));
452         fullName.append(":type=Endpoint,service=");
453         fullName.append(jmxSupport.escape(mBean.getComponentName()));
454         fullName.append(",connector=");
455         fullName.append(connector.getName());
456         fullName.append(",name=");
457         fullName.append(rawName);
458         return fullName.toString();
459     }
460 
461     protected void registerConnectorServices() throws MalformedObjectNameException,
462         NotCompliantMBeanException, MBeanRegistrationException, InstanceAlreadyExistsException
463     {
464         for (Connector connector : muleContext.getRegistry().lookupObjects(Connector.class))
465         {
466             ConnectorServiceMBean service = new ConnectorService(connector);
467             final String rawName = service.getName();
468             final String name = jmxSupport.escape(rawName);
469             final String jmxName = String.format("%s:%s%s", jmxSupport.getDomainName(muleContext, !containerMode), ConnectorServiceMBean.DEFAULT_JMX_NAME_PREFIX, name);
470             if (logger.isDebugEnabled())
471             {
472                 logger.debug("Attempting to register service with name: " + jmxName);
473             }
474             ObjectName oName = jmxSupport.getObjectName(jmxName);
475             ClassloaderSwitchingMBeanWrapper mBean = new ClassloaderSwitchingMBeanWrapper(service, ConnectorServiceMBean.class, muleContext.getExecutionClassLoader());
476             mBeanServer.registerMBean(mBean, oName);
477             logger.info("Registered Connector Service with name " + oName);
478         }
479     }
480 
481     public boolean isCreateServer()
482     {
483         return createServer;
484     }
485 
486     public void setCreateServer(boolean createServer)
487     {
488         this.createServer = createServer;
489     }
490 
491     public boolean isLocateServer()
492     {
493         return locateServer;
494     }
495 
496     public void setLocateServer(boolean locateServer)
497     {
498         this.locateServer = locateServer;
499     }
500 
501     public String getConnectorServerUrl()
502     {
503         return connectorServerUrl;
504     }
505 
506     public void setConnectorServerUrl(String connectorServerUrl)
507     {
508         this.connectorServerUrl = connectorServerUrl;
509     }
510 
511     public boolean isEnableStatistics()
512     {
513         return enableStatistics;
514     }
515 
516     public void setEnableStatistics(boolean enableStatistics)
517     {
518         this.enableStatistics = enableStatistics;
519     }
520 
521     public MBeanServer getMBeanServer()
522     {
523         return mBeanServer;
524     }
525 
526     public void setMBeanServer(MBeanServer mBeanServer)
527     {
528         this.mBeanServer = mBeanServer;
529     }
530 
531     public Map<String, Object> getConnectorServerProperties()
532     {
533         return connectorServerProperties;
534     }
535 
536     /**
537      * Setter for property 'connectorServerProperties'. Set to {@code null} to use defaults ({@link
538      * #DEFAULT_CONNECTOR_SERVER_PROPERTIES}). Pass in an empty map to use no parameters.
539      * Passing a non-empty map will replace defaults.
540      *
541      * @param connectorServerProperties Value to set for property 'connectorServerProperties'.
542      */
543     public void setConnectorServerProperties(Map<String, Object> connectorServerProperties)
544     {
545         this.connectorServerProperties = connectorServerProperties;
546     }
547 
548     public JmxSupportFactory getJmxSupportFactory()
549     {
550         return jmxSupportFactory;
551     }
552 
553     public void setJmxSupportFactory(JmxSupportFactory jmxSupportFactory)
554     {
555         this.jmxSupportFactory = jmxSupportFactory;
556     }
557 
558 
559     /**
560      * Setter for property 'credentials'.
561      *
562      * @param newCredentials Value to set for property 'credentials'.
563      */
564     public void setCredentials(final Map<String, String> newCredentials)
565     {
566         this.credentials.clear();
567         if (newCredentials != null && !newCredentials.isEmpty())
568         {
569             this.credentials.putAll(newCredentials);
570         }
571     }
572 
573     protected void unregisterMBeansIfNecessary()
574     {
575         unregisterMBeansIfNecessary(false);
576     }
577 
578     /**
579      * @param containerMode when true, MuleContext will still be exposed to enable the 'start' operation
580      */
581     protected void unregisterMBeansIfNecessary(boolean containerMode)
582     {
583         if (mBeanServer == null)
584         {
585             return;
586         }
587 
588         try
589         {
590             // note that we don't try to resolve a domain name clash here.
591             // e.g. when stopping an app via jmx, we want to obtain current domain only,
592             // but the execution thread is different, and doesn't have the resolved domain info 
593             final String domain = jmxSupport.getDomainName(muleContext, false);
594             ObjectName query = jmxSupport.getObjectName(domain + ":*");
595             Set<ObjectName> mbeans = mBeanServer.queryNames(query, null);
596             while (!mbeans.isEmpty())
597             {
598                 ObjectName name = mbeans.iterator().next();
599                 try
600                 {
601                     if (!(containerMode && MuleServiceMBean.DEFAULT_JMX_NAME.equals(name.getCanonicalKeyPropertyListString())))
602                     {
603                         mBeanServer.unregisterMBean(name);
604                     }
605                 }
606                 catch (Exception e)
607                 {
608                     logger.warn(String.format("Failed to unregister MBean: %s. Error is: %s", name, e.getMessage()));
609                 }
610 
611                 // query mbeans again, as some mbeans have cascaded unregister operations,
612                 // this prevents duplicate unregister attempts
613                 mbeans = mBeanServer.queryNames(query, null);
614 
615                 if (containerMode)
616                 {
617                     // filter out MuleContext MBean to avoid an endless loop
618                     mbeans.remove(jmxSupport.getObjectName(String.format("%s:%s", domain, MuleServiceMBean.DEFAULT_JMX_NAME)));
619                 }
620             }
621         }
622         catch (MalformedObjectNameException e)
623         {
624             logger.warn("Failed to create ObjectName query", e);
625         }
626     }
627 
628     public Registry getRmiRegistry()
629     {
630         return rmiRegistry;
631     }
632 
633     public void setRmiRegistry(Registry rmiRegistry)
634     {
635         this.rmiRegistry = rmiRegistry;
636     }
637 
638     public boolean isCreateRmiRegistry()
639     {
640         return createRmiRegistry;
641     }
642 
643     public void setCreateRmiRegistry(boolean createRmiRegistry)
644     {
645         this.createRmiRegistry = createRmiRegistry;
646     }
647 
648     protected class MuleContextStartedListener implements MuleContextNotificationListener<MuleContextNotification>
649     {
650 
651         public void onNotification(MuleContextNotification notification)
652         {
653             if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED)
654             {
655                 try
656                 {
657                     registerWrapperService();
658                     registerStatisticsService();
659                     registerMuleService();
660                     registerConfigurationService();
661                     registerModelServices();
662                     registerServiceServices();
663                     registerEndpointServices();
664                     registerConnectorServices();
665                 }
666                 catch (Exception e)
667                 {
668                     throw new MuleRuntimeException(CoreMessages.objectFailedToInitialise("MBeans"), e);
669                 }
670             }
671         }
672     }
673 
674     protected class MuleContextStoppedListener implements MuleContextNotificationListener<MuleContextNotification>
675     {
676 
677         public void onNotification(MuleContextNotification notification)
678         {
679             if (notification.getAction() == MuleContextNotification.CONTEXT_STOPPED)
680             {
681                 boolean containerMode = notification.getMuleContext().getConfiguration().isContainerMode();
682                 unregisterMBeansIfNecessary(containerMode);
683             }
684         }
685     }
686 }