1
2
3
4
5
6
7
8
9
10 package org.mule.module.management.agent;
11
12 import org.mule.AbstractAgent;
13 import org.mule.RegistryContext;
14 import org.mule.api.MuleException;
15 import org.mule.api.MuleRuntimeException;
16 import org.mule.api.context.notification.MuleContextNotificationListener;
17 import org.mule.api.context.notification.ServerNotification;
18 import org.mule.api.lifecycle.InitialisationException;
19 import org.mule.api.model.Model;
20 import org.mule.api.service.Service;
21 import org.mule.api.transport.Connector;
22 import org.mule.api.transport.MessageReceiver;
23 import org.mule.config.i18n.CoreMessages;
24 import org.mule.context.notification.MuleContextNotification;
25 import org.mule.context.notification.NotificationException;
26 import org.mule.module.management.i18n.ManagementMessages;
27 import org.mule.module.management.mbean.ConnectorService;
28 import org.mule.module.management.mbean.ConnectorServiceMBean;
29 import org.mule.module.management.mbean.EndpointService;
30 import org.mule.module.management.mbean.EndpointServiceMBean;
31 import org.mule.module.management.mbean.ModelService;
32 import org.mule.module.management.mbean.ModelServiceMBean;
33 import org.mule.module.management.mbean.MuleConfigurationService;
34 import org.mule.module.management.mbean.MuleConfigurationServiceMBean;
35 import org.mule.module.management.mbean.MuleService;
36 import org.mule.module.management.mbean.MuleServiceMBean;
37 import org.mule.module.management.mbean.ServiceService;
38 import org.mule.module.management.mbean.ServiceServiceMBean;
39 import org.mule.module.management.mbean.StatisticsService;
40 import org.mule.module.management.support.AutoDiscoveryJmxSupportFactory;
41 import org.mule.module.management.support.JmxSupport;
42 import org.mule.module.management.support.JmxSupportFactory;
43 import org.mule.module.management.support.SimplePasswordJmxAuthenticator;
44 import org.mule.transport.AbstractConnector;
45 import org.mule.util.ClassUtils;
46 import org.mule.util.StringUtils;
47
48 import java.rmi.server.ExportException;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.HashMap;
53 import java.util.Iterator;
54 import java.util.List;
55 import java.util.Map;
56
57 import javax.management.InstanceAlreadyExistsException;
58 import javax.management.MBeanRegistrationException;
59 import javax.management.MBeanServer;
60 import javax.management.MBeanServerFactory;
61 import javax.management.MalformedObjectNameException;
62 import javax.management.NotCompliantMBeanException;
63 import javax.management.ObjectName;
64 import javax.management.remote.JMXAuthenticator;
65 import javax.management.remote.JMXConnectorServer;
66 import javax.management.remote.JMXConnectorServerFactory;
67 import javax.management.remote.JMXServiceURL;
68 import javax.management.remote.rmi.RMIConnectorServer;
69
70 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
71
72 import org.apache.commons.logging.Log;
73 import org.apache.commons.logging.LogFactory;
74
75
76
77
78 public class JmxAgent extends AbstractAgent
79 {
80
81 public static final String DEFAULT_REMOTING_URI = "service:jmx:rmi:///jndi/rmi://localhost:1099/server";
82
83 public static final Map DEFAULT_CONNECTOR_SERVER_PROPERTIES;
84
85
86
87
88 public static final String DEFAULT_JMX_AUTHENTICATOR = SimplePasswordJmxAuthenticator.class.getName();
89
90
91
92
93 protected static final Log logger = LogFactory.getLog(JmxAgent.class);
94
95
96
97
98 protected boolean locateServer = true;
99
100 private boolean createServer = true;
101 private String connectorServerUrl;
102 private MBeanServer mBeanServer;
103 private JMXConnectorServer connectorServer;
104 private Map connectorServerProperties = null;
105 private boolean enableStatistics = true;
106 private List registeredMBeans = new ArrayList();
107 private final AtomicBoolean serverCreated = new AtomicBoolean(false);
108 private final AtomicBoolean initialized = new AtomicBoolean(false);
109
110 private JmxSupportFactory jmxSupportFactory = AutoDiscoveryJmxSupportFactory.getInstance();
111 private JmxSupport jmxSupport = jmxSupportFactory.getJmxSupport();
112
113
114
115
116
117 private Map credentials = new HashMap();
118
119 static
120 {
121 Map props = new HashMap(1);
122 props.put(RMIConnectorServer.JNDI_REBIND_ATTRIBUTE, "true");
123 DEFAULT_CONNECTOR_SERVER_PROPERTIES = Collections.unmodifiableMap(props);
124 }
125
126 public JmxAgent()
127 {
128 super("jmx-agent");
129 connectorServerProperties = new HashMap(DEFAULT_CONNECTOR_SERVER_PROPERTIES);
130 }
131
132
133
134
135
136
137 public String getDescription()
138 {
139 if (connectorServerUrl != null)
140 {
141 return name + ": " + connectorServerUrl;
142 }
143 else
144 {
145 return "JMX Agent";
146 }
147 }
148
149
150
151
152 public List getDependentAgents()
153 {
154 return Arrays.asList(new Class[] { RmiRegistryAgent.class });
155 }
156
157
158
159
160
161 public void initialise() throws InitialisationException
162 {
163 if (initialized.get())
164 {
165 return;
166 }
167 if (mBeanServer == null && !locateServer && !createServer)
168 {
169 throw new InitialisationException(ManagementMessages.createOrLocateShouldBeSet(), this);
170 }
171 if (mBeanServer == null && locateServer)
172 {
173 List l = MBeanServerFactory.findMBeanServer(null);
174 if (l != null && l.size() > 0)
175 {
176 mBeanServer = (MBeanServer) l.get(0);
177 }
178 }
179 if (mBeanServer == null && createServer)
180 {
181 mBeanServer = MBeanServerFactory.createMBeanServer();
182 serverCreated.set(true);
183 }
184 if (mBeanServer == null)
185 {
186 throw new InitialisationException(ManagementMessages.cannotLocateOrCreateServer(), this);
187 }
188
189
190 MuleContextNotificationListener l = new MuleContextNotificationListener()
191 {
192 public void onNotification(ServerNotification notification)
193 {
194 if (notification.getAction() == MuleContextNotification.CONTEXT_STARTED_MODELS)
195 {
196 try
197 {
198 registerWrapperService();
199 registerStatisticsService();
200 registerMuleService();
201 registerConfigurationService();
202 registerModelServices();
203 registerServiceServices();
204 registerEndpointServices();
205 registerConnectorServices();
206 }
207 catch (Exception e)
208 {
209 throw new MuleRuntimeException(CoreMessages.objectFailedToInitialise("MBeans"), e);
210 }
211 }
212 }
213 };
214
215 if (StringUtils.isBlank(muleContext.getConfiguration().getId()))
216 {
217
218 throw new IllegalArgumentException(
219 "Manager ID is mandatory when running with JmxAgent. Give your Mule configuration a valid ID.");
220 }
221
222 try
223 {
224 muleContext.registerListener(l);
225 } catch (NotificationException e) {
226 throw new InitialisationException(e, this);
227 }
228 initialized.compareAndSet(false, true);
229 }
230
231
232
233
234
235
236 public void start() throws MuleException
237 {
238 try
239 {
240 logger.info("Creating and starting JMX agent connector Server");
241 if (connectorServerUrl != null)
242 {
243 JMXServiceURL url = new JMXServiceURL(connectorServerUrl);
244 if (connectorServerProperties == null)
245 {
246 connectorServerProperties = new HashMap(DEFAULT_CONNECTOR_SERVER_PROPERTIES);
247 }
248
249
250 if (!credentials.isEmpty())
251 {
252 JMXAuthenticator jmxAuthenticator = (JMXAuthenticator)ClassUtils.instanciateClass(
253 DEFAULT_JMX_AUTHENTICATOR, ClassUtils.NO_ARGS);
254
255 ((SimplePasswordJmxAuthenticator)jmxAuthenticator).setCredentials(credentials);
256 connectorServerProperties.put(JMXConnectorServer.AUTHENTICATOR, jmxAuthenticator);
257 }
258 connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url,
259 connectorServerProperties, mBeanServer);
260 connectorServer.start();
261 }
262 }
263 catch (ExportException e)
264 {
265 throw new JmxManagementException(CoreMessages.failedToStart("Jmx Agent"), e);
266 }
267 catch (Exception e)
268 {
269 throw new JmxManagementException(CoreMessages.failedToStart("Jmx Agent"), e);
270 }
271 }
272
273 public void stop() throws MuleException
274 {
275 if (connectorServer != null)
276 {
277 try
278 {
279 connectorServer.stop();
280 }
281 catch (Exception e)
282 {
283 throw new JmxManagementException(CoreMessages.failedToStop("Jmx Connector"), e);
284 }
285 }
286 }
287
288
289
290
291 public void dispose()
292 {
293 if (mBeanServer != null)
294 {
295 for (Iterator iterator = registeredMBeans.iterator(); iterator.hasNext();)
296 {
297 ObjectName objectName = (ObjectName) iterator.next();
298 try
299 {
300 mBeanServer.unregisterMBean(objectName);
301 }
302 catch (Exception e)
303 {
304 logger.warn("Failed to unregister MBean: " + objectName + ". Error is: " + e.getMessage());
305 }
306 }
307 if (serverCreated.get())
308 {
309 MBeanServerFactory.releaseMBeanServer(mBeanServer);
310 }
311 mBeanServer = null;
312 }
313
314 initialized.set(false);
315 }
316
317
318
319
320 public void registered()
321 {
322
323 }
324
325
326
327
328 public void unregistered()
329 {
330
331 }
332
333
334
335
336
337 protected void registerWrapperService() throws MuleException
338 {
339
340 final WrapperManagerAgent wmAgent = new WrapperManagerAgent();
341 if (muleContext.getRegistry().lookupAgent(wmAgent.getName()) == null)
342 {
343 muleContext.getRegistry().registerAgent(wmAgent);
344 }
345 }
346
347
348 protected void registerStatisticsService() throws NotCompliantMBeanException, MBeanRegistrationException,
349 InstanceAlreadyExistsException, MalformedObjectNameException
350 {
351 ObjectName on = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":type=org.mule.Statistics,name=AllStatistics");
352 StatisticsService mBean = new StatisticsService();
353 mBean.setMuleContext(muleContext);
354 mBean.setEnabled(isEnableStatistics());
355 logger.debug("Registering statistics with name: " + on);
356 mBeanServer.registerMBean(mBean, on);
357 registeredMBeans.add(on);
358 }
359
360 protected void registerModelServices() throws NotCompliantMBeanException, MBeanRegistrationException,
361 InstanceAlreadyExistsException, MalformedObjectNameException
362 {
363 for (Iterator iterator = muleContext.getRegistry().lookupObjects(Model.class).iterator(); iterator.hasNext();)
364 {
365 Model model = (Model) iterator.next();
366 ModelServiceMBean serviceMBean = new ModelService(model);
367 String rawName = serviceMBean.getName() + "(" + serviceMBean.getType() + ")";
368 String name = jmxSupport.escape(rawName);
369 ObjectName on = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":type=org.mule.Model,name=" + name);
370 logger.debug("Registering model with name: " + on);
371 mBeanServer.registerMBean(serviceMBean, on);
372 registeredMBeans.add(on);
373 }
374 }
375
376 protected void registerMuleService() throws NotCompliantMBeanException, MBeanRegistrationException,
377 InstanceAlreadyExistsException, MalformedObjectNameException
378 {
379 ObjectName on = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":type=org.mule.MuleContext,name=MuleServerInfo");
380 MuleServiceMBean serviceMBean = new MuleService(muleContext);
381 logger.debug("Registering mule with name: " + on);
382 mBeanServer.registerMBean(serviceMBean, on);
383 registeredMBeans.add(on);
384 }
385
386 protected void registerConfigurationService() throws NotCompliantMBeanException, MBeanRegistrationException,
387 InstanceAlreadyExistsException, MalformedObjectNameException
388 {
389 ObjectName on = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":type=org.mule.Configuration,name=GlobalConfiguration");
390 MuleConfigurationServiceMBean serviceMBean = new MuleConfigurationService(RegistryContext.getConfiguration());
391 logger.debug("Registering configuration with name: " + on);
392 mBeanServer.registerMBean(serviceMBean, on);
393 registeredMBeans.add(on);
394 }
395
396 protected void registerServiceServices() throws NotCompliantMBeanException, MBeanRegistrationException,
397 InstanceAlreadyExistsException, MalformedObjectNameException
398 {
399 String rawName;
400 for (Iterator iterator = muleContext.getRegistry().lookupObjects(Service.class).iterator(); iterator.hasNext();)
401 {
402 rawName = ((Service) iterator.next()).getName();
403 final String name = jmxSupport.escape(rawName);
404 ObjectName on = jmxSupport.getObjectName(jmxSupport.getDomainName(muleContext) + ":type=org.mule.Service,name=" + name);
405 ServiceServiceMBean serviceMBean = new ServiceService(rawName);
406 logger.debug("Registering service with name: " + on);
407 mBeanServer.registerMBean(serviceMBean, on);
408 registeredMBeans.add(on);
409 }
410
411 }
412
413 protected void registerEndpointServices() throws NotCompliantMBeanException, MBeanRegistrationException,
414 InstanceAlreadyExistsException, MalformedObjectNameException
415 {
416 Iterator iter = muleContext.getRegistry().lookupObjects(Connector.class).iterator();
417 Connector connector;
418 while (iter.hasNext())
419 {
420 connector = (Connector) iter.next();
421 if (connector instanceof AbstractConnector)
422 {
423 for (Iterator iterator = ((AbstractConnector) connector).getReceivers().values().iterator(); iterator.hasNext();)
424 {
425 EndpointServiceMBean mBean = new EndpointService((MessageReceiver) iterator.next());
426 final String rawName = mBean.getName();
427 final String name = jmxSupport.escape(rawName);
428 if (logger.isInfoEnabled()) {
429 logger.info("Attempting to register service with name: " + jmxSupport.getDomainName(muleContext) +
430 ":type=org.mule.Endpoint,service=" +
431 jmxSupport.escape(mBean.getComponentName()) +
432 ",name=" + name);
433 }
434 ObjectName on = jmxSupport.getObjectName(
435 jmxSupport.getDomainName(muleContext) +
436 ":type=org.mule.Endpoint,service=" +
437 jmxSupport.escape(mBean.getComponentName()) +
438 ",name=" + name);
439 mBeanServer.registerMBean(mBean, on);
440 registeredMBeans.add(on);
441 logger.info("Registered Endpoint Service with name: " + on);
442 }
443 }
444 else
445 {
446 logger.warn("Connector: " + connector
447 + " is not an istance of AbstractConnector, cannot obtain Endpoint MBeans from it");
448 }
449
450 }
451 }
452
453 protected void registerConnectorServices() throws
454 MalformedObjectNameException,
455 NotCompliantMBeanException,
456 MBeanRegistrationException,
457 InstanceAlreadyExistsException
458 {
459 Iterator iter = muleContext.getRegistry().lookupObjects(Connector.class).iterator();
460 while (iter.hasNext())
461 {
462 Connector connector = (Connector) iter.next();
463 ConnectorServiceMBean mBean = new ConnectorService(connector);
464 final String rawName = mBean.getName();
465 final String name = jmxSupport.escape(rawName);
466 final String stringName = jmxSupport.getDomainName(muleContext) + ":type=org.mule.Connector,name=" + name;
467 if (logger.isDebugEnabled())
468 {
469 logger.debug("Attempting to register service with name: " + stringName);
470 }
471 ObjectName oName = jmxSupport.getObjectName(stringName);
472 mBeanServer.registerMBean(mBean, oName);
473 registeredMBeans.add(oName);
474 logger.info("Registered Connector Service with name " + oName);
475 }
476 }
477
478
479
480
481 public boolean isCreateServer()
482 {
483 return createServer;
484 }
485
486
487
488
489 public void setCreateServer(boolean createServer)
490 {
491 this.createServer = createServer;
492 }
493
494
495
496
497 public boolean isLocateServer()
498 {
499 return locateServer;
500 }
501
502
503
504
505 public void setLocateServer(boolean locateServer)
506 {
507 this.locateServer = locateServer;
508 }
509
510
511
512
513 public String getConnectorServerUrl()
514 {
515 return connectorServerUrl;
516 }
517
518
519
520
521 public void setConnectorServerUrl(String connectorServerUrl)
522 {
523 this.connectorServerUrl = connectorServerUrl;
524 }
525
526
527
528
529 public boolean isEnableStatistics()
530 {
531 return enableStatistics;
532 }
533
534
535
536
537 public void setEnableStatistics(boolean enableStatistics)
538 {
539 this.enableStatistics = enableStatistics;
540 }
541
542
543
544
545 public MBeanServer getMBeanServer()
546 {
547 return mBeanServer;
548 }
549
550
551
552
553 public void setMBeanServer(MBeanServer mBeanServer)
554 {
555 this.mBeanServer = mBeanServer;
556 }
557
558
559
560
561
562
563 public Map getConnectorServerProperties()
564 {
565 return connectorServerProperties;
566 }
567
568
569
570
571
572
573
574
575 public void setConnectorServerProperties(Map connectorServerProperties)
576 {
577 this.connectorServerProperties = connectorServerProperties;
578 }
579
580
581
582
583
584
585
586 public JmxSupportFactory getJmxSupportFactory()
587 {
588 return jmxSupportFactory;
589 }
590
591
592
593
594
595
596 public void setJmxSupportFactory(JmxSupportFactory jmxSupportFactory)
597 {
598 this.jmxSupportFactory = jmxSupportFactory;
599 }
600
601
602
603
604
605
606
607 public void setCredentials(final Map newCredentials)
608 {
609 this.credentials.clear();
610 if (newCredentials != null && !newCredentials.isEmpty())
611 {
612 this.credentials.putAll(newCredentials);
613 }
614 }
615
616 }