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 */
017 package org.apache.servicemix.jbi.management;
018
019 import java.io.IOException;
020 import java.util.Collection;
021 import java.util.Iterator;
022 import java.util.LinkedHashMap;
023 import java.util.Map;
024 import java.util.concurrent.ConcurrentHashMap;
025 import java.util.concurrent.ExecutorService;
026 import java.util.concurrent.Executors;
027
028 import javax.jbi.JBIException;
029 import javax.management.JMException;
030 import javax.management.MBeanAttributeInfo;
031 import javax.management.MBeanOperationInfo;
032 import javax.management.MBeanServer;
033 import javax.management.MalformedObjectNameException;
034 import javax.management.ObjectName;
035
036 import org.apache.commons.logging.Log;
037 import org.apache.commons.logging.LogFactory;
038 import org.apache.servicemix.jbi.container.EnvironmentContext;
039 import org.apache.servicemix.jbi.container.JBIContainer;
040 import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
041
042 /**
043 * Management Context applied to a ServiceMix container
044 *
045 * @version $Revision: 665810 $
046 */
047 public class ManagementContext extends BaseSystemService implements ManagementContextMBean {
048 /**
049 * Default servicemix domain
050 */
051 public static final String DEFAULT_DOMAIN = "org.apache.servicemix";
052
053 public static final String DEFAULT_CONNECTOR_PATH = "/jmxrmi";
054
055 public static final int DEFAULT_CONNECTOR_PORT = 1099;
056
057 private static final Log LOG = LogFactory.getLog(ManagementContext.class);
058
059 protected Map<String, ObjectName> systemServices = new ConcurrentHashMap<String, ObjectName>();
060
061 private Map<ObjectName, Object> beanMap = new ConcurrentHashMap<ObjectName, Object>();
062
063 private MBeanServerContext mbeanServerContext = new MBeanServerContext();
064
065 private ExecutorService executors;
066
067 /**
068 * Default Constructor
069 */
070 public ManagementContext() {
071 mbeanServerContext.setJmxDomainName(DEFAULT_DOMAIN);
072 }
073
074 /**
075 * Get the Description of the item
076 *
077 * @return the description
078 */
079 public String getDescription() {
080 return "JMX Management";
081 }
082
083 /**
084 * Get the MBeanServer
085 *
086 * @return the MBeanServer
087 */
088 public MBeanServer getMBeanServer() {
089 return mbeanServerContext.getMBeanServer();
090 }
091
092 /**
093 * @return the domain
094 */
095 public String getJmxDomainName() {
096 return mbeanServerContext.getJmxDomainName();
097 }
098
099 /**
100 * @return Returns the useMBeanServer.
101 */
102 public boolean isUseMBeanServer() {
103 return mbeanServerContext.isUseMBeanServer();
104 }
105
106 /**
107 * @param useMBeanServer
108 * The useMBeanServer to set.
109 */
110 public void setUseMBeanServer(boolean useMBeanServer) {
111 mbeanServerContext.setUseMBeanServer(useMBeanServer);
112 }
113
114 /**
115 * @return Returns the createMBeanServer flag.
116 */
117 public boolean isCreateMBeanServer() {
118 return mbeanServerContext.isCreateMBeanServer();
119 }
120
121 /**
122 * @param enableJMX
123 * Set createMBeanServer.
124 */
125 public void setCreateMBeanServer(boolean enableJMX) {
126 mbeanServerContext.setCreateMBeanServer(enableJMX);
127 }
128
129 public void setNamingPort(int portNum) {
130 mbeanServerContext.setConnectorPort(portNum);
131 }
132
133 public int getNamingPort() {
134 return mbeanServerContext.getConnectorPort();
135 }
136
137 public boolean isCreateJmxConnector() {
138 return mbeanServerContext.isCreateConnector();
139 }
140
141 public void setCreateJmxConnector(boolean createJmxConnector) {
142 mbeanServerContext.setCreateConnector(createJmxConnector);
143 }
144
145 /**
146 * Initialize the ManagementContext
147 *
148 * @param container
149 * @param server
150 * @throws JBIException
151 *
152 */
153 public void init(JBIContainer container, MBeanServer server) throws JBIException {
154 if (container.isEmbedded() && server == null) {
155 mbeanServerContext.setUseMBeanServer(false);
156 mbeanServerContext.setCreateMBeanServer(false);
157 mbeanServerContext.setCreateConnector(false);
158 }
159 mbeanServerContext.setMBeanServer(server);
160 try {
161 mbeanServerContext.start();
162 } catch (IOException e) {
163 LOG.error("Failed to start mbeanServerContext", e);
164 }
165 this.executors = Executors.newCachedThreadPool();
166 super.init(container);
167 }
168
169 protected Class<ManagementContextMBean> getServiceMBean() {
170 return ManagementContextMBean.class;
171 }
172
173 /**
174 * Start the item.
175 *
176 * @exception JBIException
177 * if the item fails to start.
178 */
179 public void start() throws JBIException {
180 super.start();
181 }
182
183 /**
184 * Stop the item. This suspends current messaging activities.
185 *
186 * @exception JBIException
187 * if the item fails to stop.
188 */
189 public void stop() throws JBIException {
190 super.stop();
191 }
192
193 /**
194 * Shut down the item. The releases resources, preparatory to
195 * uninstallation.
196 *
197 * @exception JBIException
198 * if the item fails to shut down.
199 */
200 public void shutDown() throws JBIException {
201 super.shutDown();
202 // Unregister all mbeans
203 ObjectName[] beans = beanMap.keySet().toArray(new ObjectName[beanMap.size()]);
204 for (int i = 0; i < beans.length; i++) {
205 try {
206 unregisterMBean(beans[i]);
207 } catch (Exception e) {
208 LOG.debug("Could not unregister mbean", e);
209 }
210 }
211 try {
212 mbeanServerContext.stop();
213 } catch (IOException e) {
214 LOG.debug("Failed to shutdown mbeanServerContext cleanly", e);
215 }
216 executors.shutdown();
217 }
218
219 /**
220 * Get a list of all binding components currently installed.
221 *
222 * @return array of JMX object names of all installed BCs.
223 */
224 public ObjectName[] getBindingComponents() {
225 return container.getRegistry().getBindingComponents();
226 }
227
228 /**
229 * Lookup a JBI Installable Component by its unique name.
230 *
231 * @param componentName -
232 * is the name of the BC or SE.
233 * @return the JMX object name of the component's LifeCycle MBean or null.
234 */
235 public ObjectName getComponentByName(String componentName) {
236 ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
237 return component != null ? component.getMBeanName() : null;
238 }
239
240 /**
241 * Get a list of all engines currently installed.
242 *
243 * @return array of JMX object names of all installed SEs.
244 */
245 public ObjectName[] getEngineComponents() {
246 return container.getRegistry().getEngineComponents();
247 }
248
249 /**
250 * @return an array of ObjectNames for all Pojo components
251 */
252 public ObjectName[] getPojoComponents() {
253 return container.getRegistry().getPojoComponents();
254 }
255
256 /**
257 * Return current version and other info about this JBI Framework.
258 *
259 * @return info String
260 */
261 public String getSystemInfo() {
262 return "ServiceMix JBI Container: version: " + EnvironmentContext.getVersion();
263 }
264
265 /**
266 * Lookup a system service by name.
267 *
268 * @param serviceName -
269 * is the name of the system service
270 * @return the JMX object name of the service or null
271 */
272 public ObjectName getSystemService(String serviceName) {
273 return systemServices.get(serviceName);
274 }
275
276 /**
277 * Looks up all JBI Framework System Services currently installed.
278 *
279 * @return array of JMX object names of system services
280 */
281 public ObjectName[] getSystemServices() {
282 ObjectName[] result = null;
283 Collection<ObjectName> col = systemServices.values();
284 result = new ObjectName[col.size()];
285 col.toArray(result);
286 return result;
287 }
288
289 /**
290 * Check if a given JBI Installable Component is a Binding Component.
291 *
292 * @param componentName -
293 * the unique name of the component
294 * @return true if the component is a binding
295 */
296 public boolean isBinding(String componentName) {
297 ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
298 return component != null ? component.isBinding() : false;
299 }
300
301 /**
302 * Check if a given JBI Component is a service engine.
303 *
304 * @param componentName -
305 * the unique name of the component
306 * @return true if the component is a service engine
307 */
308 public boolean isEngine(String componentName) {
309 ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
310 return component != null ? component.isEngine() : false;
311 }
312
313 /**
314 * Start a Component
315 *
316 * @param componentName
317 * @return the status
318 * @throws JBIException
319 */
320 public String startComponent(String componentName) throws JBIException {
321 String result = "NOT FOUND: " + componentName;
322 ObjectName objName = getComponentByName(componentName);
323 if (objName != null) {
324 ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
325 if (mbean != null) {
326 mbean.start();
327 result = mbean.getCurrentState();
328 }
329 }
330 return result;
331 }
332
333 /**
334 * Stop a Component
335 *
336 * @param componentName
337 * @return the status
338 * @throws JBIException
339 */
340 public String stopComponent(String componentName) throws JBIException {
341 String result = "NOT FOUND: " + componentName;
342 ObjectName objName = getComponentByName(componentName);
343 if (objName != null) {
344 ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
345 if (mbean != null) {
346 mbean.stop();
347 result = mbean.getCurrentState();
348 }
349 }
350 return result;
351 }
352
353 /**
354 * Shutdown a Component
355 *
356 * @param componentName
357 * @return the status
358 * @throws JBIException
359 */
360 public String shutDownComponent(String componentName) throws JBIException {
361 String result = "NOT FOUND: " + componentName;
362 ObjectName objName = getComponentByName(componentName);
363 if (objName != null) {
364 ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
365 if (mbean != null) {
366 mbean.shutDown();
367 result = mbean.getCurrentState();
368 }
369 }
370 return result;
371 }
372
373 /**
374 * Formulate and return the MBean ObjectName of a custom control MBean for a
375 * JBI component.
376 *
377 * @param type
378 * @param name
379 * @return the JMX ObjectName of the MBean, or <code>null</code> if
380 * <code>customName</code> is invalid.
381 */
382 public ObjectName createCustomComponentMBeanName(String type, String name) {
383 Map<String, String> result = new LinkedHashMap<String, String>();
384 result.put("ContainerName", container.getName());
385 result.put("Type", "Component");
386 result.put("Name", sanitizeString(name));
387 result.put("SubType", sanitizeString(type));
388 return createObjectName(result);
389 }
390
391 /**
392 * Create an ObjectName
393 *
394 * @param provider
395 * @return the ObjectName
396 */
397 public ObjectName createObjectName(MBeanInfoProvider provider) {
398 Map<String, String> props = createObjectNameProps(provider);
399 return createObjectName(props);
400 }
401
402 /**
403 * Create an ObjectName
404 *
405 * @param name
406 *
407 * @return the ObjectName
408 */
409 public ObjectName createObjectName(String name) {
410 ObjectName result = null;
411 try {
412 result = new ObjectName(name);
413 } catch (MalformedObjectNameException e) {
414 // shouldn't happen
415 String error = "Could not create ObjectName for " + name;
416 LOG.error(error, e);
417 throw new RuntimeException(error);
418 }
419 return result;
420 }
421
422 /**
423 * Create an ObjectName
424 *
425 * @param domain
426 *
427 * @return the ObjectName
428 */
429 public ObjectName createObjectName(String domain, Map<String, String> props) {
430 StringBuffer sb = new StringBuffer();
431 sb.append(domain).append(':');
432 int i = 0;
433 for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
434 Map.Entry entry = (Map.Entry) it.next();
435 if (i++ > 0) {
436 sb.append(",");
437 }
438 sb.append(entry.getKey()).append("=").append(entry.getValue());
439 }
440 ObjectName result = null;
441 try {
442 result = new ObjectName(sb.toString());
443 } catch (MalformedObjectNameException e) {
444 // shouldn't happen
445 String error = "Could not create ObjectName for " + props;
446 LOG.error(error, e);
447 throw new RuntimeException(error);
448 }
449 return result;
450 }
451
452 /**
453 * Create an ObjectName
454 *
455 * @param props
456 * @return the ObjectName
457 */
458 public ObjectName createObjectName(Map<String, String> props) {
459 return createObjectName(getJmxDomainName(), props);
460 }
461
462 /**
463 * Create a String used to create an ObjectName
464 *
465 * @param provider
466 * @return the ObjectName
467 */
468 public Map<String, String> createObjectNameProps(MBeanInfoProvider provider) {
469 return createObjectNameProps(provider, false);
470 }
471
472 /**
473 * Create a String used to create an ObjectName
474 *
475 * @param provider
476 * @return the ObjectName
477 */
478 public Map<String, String> createObjectNameProps(MBeanInfoProvider provider, boolean subTypeBeforeName) {
479 Map<String, String> result = new LinkedHashMap<String, String>();
480 result.put("ContainerName", container.getName());
481 result.put("Type", sanitizeString(provider.getType()));
482 if (subTypeBeforeName && provider.getSubType() != null) {
483 result.put("SubType", sanitizeString(provider.getSubType()));
484 }
485 result.put("Name", sanitizeString(provider.getName()));
486 if (!subTypeBeforeName && provider.getSubType() != null) {
487 result.put("SubType", sanitizeString(provider.getSubType()));
488 }
489 return result;
490 }
491
492 /**
493 * The ':' and '/' characters are reserved in ObjectNames
494 *
495 * @param in
496 * @return sanitized String
497 */
498 private static String sanitizeString(String in) {
499 String result = null;
500 if (in != null) {
501 result = in.replace(':', '_');
502 result = result.replace('/', '_');
503 result = result.replace('\\', '_');
504 result = result.replace('?', '_');
505 result = result.replace('=', '_');
506 result = result.replace(',', '_');
507 }
508 return result;
509 }
510
511 /**
512 * Register an MBean
513 *
514 * @param resource
515 * @param name
516 * @param interfaceMBean
517 * @throws JMException
518 */
519 public void registerMBean(ObjectName name, MBeanInfoProvider resource, Class interfaceMBean) throws JMException {
520 registerMBean(name, resource, interfaceMBean, resource.getDescription());
521 }
522
523 /**
524 * Register an MBean
525 *
526 * @param resource
527 * @param name
528 * @param interfaceMBean
529 * @param description
530 * @throws JMException
531 */
532 public void registerMBean(ObjectName name, Object resource, Class interfaceMBean, String description) throws JMException {
533 if (mbeanServerContext.getMBeanServer() != null) {
534 Object mbean = MBeanBuilder.buildStandardMBean(resource, interfaceMBean, description, executors);
535 if (mbeanServerContext.getMBeanServer().isRegistered(name)) {
536 mbeanServerContext.getMBeanServer().unregisterMBean(name);
537 }
538 mbeanServerContext.getMBeanServer().registerMBean(mbean, name);
539 beanMap.put(name, resource);
540 }
541 }
542
543 /**
544 * Retrive an System ObjectName
545 *
546 * @param domainName
547 * @param containerName
548 * @param interfaceType
549 * @return the ObjectName
550 */
551 public static ObjectName getSystemObjectName(String domainName, String containerName, Class interfaceType) {
552 String tmp = domainName + ":ContainerName=" + containerName + ",Type=SystemService,Name=" + getSystemServiceName(interfaceType);
553 ObjectName result = null;
554 try {
555 result = new ObjectName(tmp);
556 } catch (MalformedObjectNameException e) {
557 LOG.error("Failed to build ObjectName:", e);
558 } catch (NullPointerException e) {
559 LOG.error("Failed to build ObjectName:", e);
560 }
561 return result;
562 }
563
564 public static String getSystemServiceName(Class interfaceType) {
565 String name = interfaceType.getName();
566 name = name.substring(name.lastIndexOf('.') + 1);
567 if (name.endsWith("MBean")) {
568 name = name.substring(0, name.length() - 5);
569 }
570 return name;
571 }
572
573 public static ObjectName getContainerObjectName(String domainName, String containerName) {
574 String tmp = domainName + ":ContainerName=" + containerName + ",Type=JBIContainer";
575 ObjectName result = null;
576 try {
577 result = new ObjectName(tmp);
578 } catch (MalformedObjectNameException e) {
579 LOG.debug("Unable to build ObjectName", e);
580 } catch (NullPointerException e) {
581 LOG.debug("Unable to build ObjectName", e);
582 }
583 return result;
584 }
585
586 /**
587 * Register a System service
588 *
589 * @param service
590 * @param interfaceType
591 * @throws JBIException
592 */
593 public void registerSystemService(BaseSystemService service, Class interfaceType) throws JBIException {
594 try {
595
596 String name = service.getName();
597 if (systemServices.containsKey(name)) {
598 throw new JBIException("A system service for the name " + name + " is already registered");
599 }
600 ObjectName objName = createObjectName(service);
601 if (LOG.isDebugEnabled()) {
602 LOG.debug("Registering system service: " + objName);
603 }
604 registerMBean(objName, service, interfaceType, service.getDescription());
605 systemServices.put(name, objName);
606 } catch (MalformedObjectNameException e) {
607 throw new JBIException(e);
608 } catch (JMException e) {
609 throw new JBIException(e);
610 }
611 }
612
613 /**
614 * Unregister a System service
615 *
616 * @param service
617 * @throws JBIException
618 */
619 public void unregisterSystemService(BaseSystemService service) throws JBIException {
620 String name = service.getName();
621 if (!systemServices.containsKey(name)) {
622 throw new JBIException("A system service for the name " + name + " is not registered");
623 }
624 ObjectName objName = systemServices.remove(name);
625 if (LOG.isDebugEnabled()) {
626 LOG.debug("Unregistering system service: " + objName);
627 }
628 unregisterMBean(objName);
629 }
630
631 /**
632 * Unregister an MBean
633 *
634 * @param name
635 * @throws JBIException
636 */
637 public void unregisterMBean(ObjectName name) throws JBIException {
638 try {
639 mbeanServerContext.unregisterMBean(name);
640 beanMap.remove(name);
641 } catch (JMException e) {
642 LOG.error("Failed to unregister mbean: " + name, e);
643 throw new JBIException(e);
644 }
645 }
646
647 /**
648 * Unregister an MBean
649 *
650 * @param bean
651 * @throws JBIException
652 */
653 public void unregisterMBean(Object bean) throws JBIException {
654 for (Iterator i = beanMap.entrySet().iterator(); i.hasNext();) {
655 Map.Entry entry = (Map.Entry) i.next();
656 if (entry.getValue() == bean) {
657 ObjectName name = (ObjectName) entry.getKey();
658 unregisterMBean(name);
659 break;
660 }
661 }
662 }
663
664 /**
665 * Get an array of MBeanOperationInfo
666 *
667 * @return array of OperationInfos
668 * @throws JMException
669 */
670 public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
671 AttributeInfoHelper helper = new AttributeInfoHelper();
672 helper.addAttribute(getObjectToManage(), "bindingComponents", "Get list of all binding components");
673 helper.addAttribute(getObjectToManage(), "engineComponents", "Get list of all engine components");
674 helper.addAttribute(getObjectToManage(), "pojoComponents", "Get list of all pojo components");
675 helper.addAttribute(getObjectToManage(), "systemInfo", "Return current version");
676 helper.addAttribute(getObjectToManage(), "systemServices", "Get list of system services");
677 return AttributeInfoHelper.join(super.getAttributeInfos(), helper.getAttributeInfos());
678 }
679
680 public MBeanOperationInfo[] getOperationInfos() throws JMException {
681 OperationInfoHelper helper = new OperationInfoHelper();
682 ParameterHelper ph = helper.addOperation(getObjectToManage(), "getComponentByName", 1, "look up Component by name");
683 ph.setDescription(0, "name", "Component name");
684 ph = helper.addOperation(getObjectToManage(), "getSystemService", 1, "look up System service by name");
685 ph.setDescription(0, "name", "System name");
686 ph = helper.addOperation(getObjectToManage(), "isBinding", 1, "Is Component a binding Component?");
687 ph.setDescription(0, "name", "Component name");
688 ph = helper.addOperation(getObjectToManage(), "isEngine", 1, "Is Component a service engine?");
689 ph.setDescription(0, "name", "Component name");
690 return OperationInfoHelper.join(super.getOperationInfos(), helper.getOperationInfos());
691 }
692
693 }