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