blob: 57eb3318aab6581fcaf0136b0ecea579250cf4a5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.servicemix.jbi.management;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.jbi.JBIException;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import org.apache.servicemix.jbi.container.EnvironmentContext;
import org.apache.servicemix.jbi.container.JBIContainer;
import org.apache.servicemix.jbi.framework.ComponentMBeanImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Management Context applied to a ServiceMix container
*
* @version $Revision$
*/
public class ManagementContext extends BaseSystemService implements ManagementContextMBean {
/**
* Default ServiceMix domain
*/
public static final String DEFAULT_DOMAIN = "org.apache.servicemix";
public static final String DEFAULT_CONNECTOR_PATH = "/jmxrmi";
public static final int DEFAULT_CONNECTOR_PORT = 1099;
private static final transient Logger LOGGER = LoggerFactory.getLogger(ManagementContext.class);
protected Map<String, ObjectName> systemServices = new ConcurrentHashMap<String, ObjectName>();
private Map<ObjectName, Object> beanMap = new ConcurrentHashMap<ObjectName, Object>();
private MBeanServerContext mbeanServerContext = new MBeanServerContext();
private ExecutorService executors;
/**
* Default Constructor
*/
public ManagementContext() {
mbeanServerContext.setJmxDomainName(DEFAULT_DOMAIN);
}
/**
* Get the Description of the item
*
* @return the description
*/
public String getDescription() {
return "JMX Management";
}
/**
* Get the MBeanServer
*
* @return the MBeanServer
*/
public MBeanServer getMBeanServer() {
return mbeanServerContext.getMBeanServer();
}
protected void setMBeanServer(MBeanServer server) {
mbeanServerContext.setMBeanServer(server);
}
/**
* @return the domain
*/
public String getJmxDomainName() {
return mbeanServerContext.getJmxDomainName();
}
/**
* @return Returns the useMBeanServer.
*/
public boolean isUseMBeanServer() {
return mbeanServerContext.isUseMBeanServer();
}
/**
* @param useMBeanServer
* The useMBeanServer to set.
*/
public void setUseMBeanServer(boolean useMBeanServer) {
mbeanServerContext.setUseMBeanServer(useMBeanServer);
}
/**
* @return Returns the createMBeanServer flag.
*/
public boolean isCreateMBeanServer() {
return mbeanServerContext.isCreateMBeanServer();
}
/**
* @param enableJMX
* Set createMBeanServer.
*/
public void setCreateMBeanServer(boolean enableJMX) {
mbeanServerContext.setCreateMBeanServer(enableJMX);
}
public void setNamingPort(int portNum) {
mbeanServerContext.setConnectorPort(portNum);
}
public int getNamingPort() {
return mbeanServerContext.getConnectorPort();
}
public boolean isCreateJmxConnector() {
return mbeanServerContext.isCreateConnector();
}
public void setCreateJmxConnector(boolean createJmxConnector) {
mbeanServerContext.setCreateConnector(createJmxConnector);
}
/**
* Initialize the ManagementContext
*
* @param container
* @param server
* @throws JBIException
*
*/
public void init(JBIContainer container, MBeanServer server) throws JBIException {
if (container.isEmbedded() && server == null) {
mbeanServerContext.setUseMBeanServer(false);
mbeanServerContext.setCreateMBeanServer(false);
mbeanServerContext.setCreateConnector(false);
}
mbeanServerContext.setMBeanServer(server);
try {
mbeanServerContext.start();
} catch (IOException e) {
LOGGER.error("Failed to start mbeanServerContext", e);
}
this.executors = Executors.newCachedThreadPool();
super.init(container);
}
protected Class<ManagementContextMBean> getServiceMBean() {
return ManagementContextMBean.class;
}
/**
* Start the item.
*
* @exception JBIException
* if the item fails to start.
*/
public void start() throws JBIException {
super.start();
}
/**
* Stop the item. This suspends current messaging activities.
*
* @exception JBIException
* if the item fails to stop.
*/
public void stop() throws JBIException {
super.stop();
}
/**
* Shut down the item. The releases resources, preparatory to
* uninstallation.
*
* @exception JBIException
* if the item fails to shut down.
*/
public void shutDown() throws JBIException {
super.shutDown();
// Unregister all mbeans
ObjectName[] beans = beanMap.keySet().toArray(new ObjectName[beanMap.size()]);
for (int i = 0; i < beans.length; i++) {
try {
unregisterMBean(beans[i]);
} catch (Exception e) {
LOGGER.debug("Could not unregister mbean", e);
}
}
try {
mbeanServerContext.stop();
} catch (IOException e) {
LOGGER.debug("Failed to shutdown mbeanServerContext cleanly", e);
}
executors.shutdown();
}
/**
* Get a list of all binding components currently installed.
*
* @return array of JMX object names of all installed BCs.
*/
public ObjectName[] getBindingComponents() {
return container.getRegistry().getBindingComponents();
}
/**
* Lookup a JBI Installable Component by its unique name.
*
* @param componentName -
* is the name of the BC or SE.
* @return the JMX object name of the component's LifeCycle MBean or null.
*/
public ObjectName getComponentByName(String componentName) {
ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
return component != null ? component.getMBeanName() : null;
}
/**
* Get a list of all engines currently installed.
*
* @return array of JMX object names of all installed SEs.
*/
public ObjectName[] getEngineComponents() {
return container.getRegistry().getEngineComponents();
}
/**
* @return an array of ObjectNames for all Pojo components
*/
public ObjectName[] getPojoComponents() {
return container.getRegistry().getPojoComponents();
}
/**
* Return current version and other info about this JBI Framework.
*
* @return info String
*/
public String getSystemInfo() {
return "ServiceMix JBI Container: version: " + EnvironmentContext.getVersion();
}
/**
* Lookup a system service by name.
*
* @param serviceName -
* is the name of the system service
* @return the JMX object name of the service or null
*/
public ObjectName getSystemService(String serviceName) {
return systemServices.get(serviceName);
}
/**
* Looks up all JBI Framework System Services currently installed.
*
* @return array of JMX object names of system services
*/
public ObjectName[] getSystemServices() {
ObjectName[] result = null;
Collection<ObjectName> col = systemServices.values();
result = new ObjectName[col.size()];
col.toArray(result);
return result;
}
/**
* Check if a given JBI Installable Component is a Binding Component.
*
* @param componentName -
* the unique name of the component
* @return true if the component is a binding
*/
public boolean isBinding(String componentName) {
ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
return component != null ? component.isBinding() : false;
}
/**
* Check if a given JBI Component is a service engine.
*
* @param componentName -
* the unique name of the component
* @return true if the component is a service engine
*/
public boolean isEngine(String componentName) {
ComponentMBeanImpl component = container.getRegistry().getComponent(componentName);
return component != null ? component.isEngine() : false;
}
/**
* Start a Component
*
* @param componentName
* @return the status
* @throws JBIException
*/
public String startComponent(String componentName) throws JBIException {
String result = "NOT FOUND: " + componentName;
ObjectName objName = getComponentByName(componentName);
if (objName != null) {
ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
if (mbean != null) {
mbean.start();
result = mbean.getCurrentState();
}
}
return result;
}
/**
* Stop a Component
*
* @param componentName
* @return the status
* @throws JBIException
*/
public String stopComponent(String componentName) throws JBIException {
String result = "NOT FOUND: " + componentName;
ObjectName objName = getComponentByName(componentName);
if (objName != null) {
ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
if (mbean != null) {
mbean.stop();
result = mbean.getCurrentState();
}
}
return result;
}
/**
* Shutdown a Component
*
* @param componentName
* @return the status
* @throws JBIException
*/
public String shutDownComponent(String componentName) throws JBIException {
String result = "NOT FOUND: " + componentName;
ObjectName objName = getComponentByName(componentName);
if (objName != null) {
ComponentMBeanImpl mbean = (ComponentMBeanImpl) beanMap.get(objName);
if (mbean != null) {
mbean.shutDown();
result = mbean.getCurrentState();
}
}
return result;
}
/**
* Formulate and return the MBean ObjectName of a custom control MBean for a
* JBI component.
*
* @param type
* @param name
* @return the JMX ObjectName of the MBean, or <code>null</code> if
* <code>customName</code> is invalid.
*/
public ObjectName createCustomComponentMBeanName(String type, String name) {
Map<String, String> result = new LinkedHashMap<String, String>();
result.put("ContainerName", container.getName());
result.put("Type", "Component");
result.put("Name", sanitizeString(name));
result.put("SubType", sanitizeString(type));
return createObjectName(result);
}
/**
* Create an ObjectName
*
* @param provider
* @return the ObjectName
*/
public ObjectName createObjectName(MBeanInfoProvider provider) {
Map<String, String> props = createObjectNameProps(provider);
return createObjectName(props);
}
/**
* Create an ObjectName
*
* @param name
*
* @return the ObjectName
*/
public ObjectName createObjectName(String name) {
ObjectName result = null;
try {
result = new ObjectName(name);
} catch (MalformedObjectNameException e) {
// shouldn't happen
String error = "Could not create ObjectName for " + name;
LOGGER.error(error, e);
throw new RuntimeException(error);
}
return result;
}
/**
* Create an ObjectName
*
* @param domain
*
* @return the ObjectName
*/
public ObjectName createObjectName(String domain, Map<String, String> props) {
StringBuffer sb = new StringBuffer();
sb.append(domain).append(':');
int i = 0;
for (Iterator it = props.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
if (i++ > 0) {
sb.append(",");
}
sb.append(entry.getKey()).append("=").append(entry.getValue());
}
ObjectName result = null;
try {
result = new ObjectName(sb.toString());
} catch (MalformedObjectNameException e) {
// shouldn't happen
String error = "Could not create ObjectName for " + props;
LOGGER.error(error, e);
throw new RuntimeException(error);
}
return result;
}
/**
* Create an ObjectName
*
* @param props
* @return the ObjectName
*/
public ObjectName createObjectName(Map<String, String> props) {
return createObjectName(getJmxDomainName(), props);
}
/**
* Create a String used to create an ObjectName
*
* @param provider
* @return the ObjectName
*/
public Map<String, String> createObjectNameProps(MBeanInfoProvider provider) {
return createObjectNameProps(provider, false);
}
/**
* Create a String used to create an ObjectName
*
* @param provider
* @return the ObjectName
*/
public Map<String, String> createObjectNameProps(MBeanInfoProvider provider, boolean subTypeBeforeName) {
Map<String, String> result = new LinkedHashMap<String, String>();
result.put("ContainerName", container.getName());
result.put("Type", sanitizeString(provider.getType()));
if (subTypeBeforeName && provider.getSubType() != null) {
result.put("SubType", sanitizeString(provider.getSubType()));
}
result.put("Name", sanitizeString(provider.getName()));
if (!subTypeBeforeName && provider.getSubType() != null) {
result.put("SubType", sanitizeString(provider.getSubType()));
}
return result;
}
/**
* The ':' and '/' characters are reserved in ObjectNames
*
* @param in
* @return sanitized String
*/
private static String sanitizeString(String in) {
String result = null;
if (in != null) {
result = in.replace(':', '_');
result = result.replace('/', '_');
result = result.replace('\\', '_');
result = result.replace('?', '_');
result = result.replace('=', '_');
result = result.replace(',', '_');
}
return result;
}
/**
* Register an MBean
*
* @param resource
* @param name
* @param interfaceMBean
* @throws JMException
*/
public void registerMBean(ObjectName name, MBeanInfoProvider resource, Class interfaceMBean) throws JMException {
registerMBean(name, resource, interfaceMBean, resource.getDescription());
}
/**
* Register an MBean
*
* @param resource
* @param name
* @param interfaceMBean
* @param description
* @throws JMException
*/
public ObjectName registerMBean(ObjectName name, Object resource, Class interfaceMBean, String description) throws JMException {
if (mbeanServerContext.getMBeanServer() != null) {
Object mbean = MBeanBuilder.buildStandardMBean(resource, interfaceMBean, description, executors);
return registerMBean(name, resource, mbean);
} else {
return name;
}
}
/*
* Register an MBean for a given resource, specifying the object name and the actual MBean implementation
*
* @param name the MBean's ObjectName
* @param resource the original bean for which the MBean is a wrapper
* @param mbean the MBean implementation
*/
protected ObjectName registerMBean(ObjectName name, Object resource, Object mbean)
throws InstanceNotFoundException, MBeanRegistrationException, InstanceAlreadyExistsException, NotCompliantMBeanException {
if (mbeanServerContext.getMBeanServer().isRegistered(name)) {
mbeanServerContext.getMBeanServer().unregisterMBean(name);
}
ObjectName objectName = mbeanServerContext.getMBeanServer().registerMBean(mbean, name).getObjectName();
beanMap.put(objectName, resource);
return objectName;
}
/**
* Retrive an System ObjectName
*
* @param domainName
* @param containerName
* @param interfaceType
* @return the ObjectName
*/
public static ObjectName getSystemObjectName(String domainName, String containerName, Class interfaceType) {
String tmp = domainName + ":ContainerName=" + containerName + ",Type=SystemService,Name=" + getSystemServiceName(interfaceType);
ObjectName result = null;
try {
result = new ObjectName(tmp);
} catch (MalformedObjectNameException e) {
LOGGER.error("Failed to build ObjectName:", e);
} catch (NullPointerException e) {
LOGGER.error("Failed to build ObjectName:", e);
}
return result;
}
/**
* Retrieve an ObjectName instance that can be used for querying system service mbean instances
*
* @param domainName
* @param containerName
* @param interfaceType
* @return
*/
public static ObjectName getSystemObjectNameQuery(String domainName, String containerName, Class interfaceType) {
ObjectName result = null;
try {
result = new ObjectName(String.format("%s,*", getSystemObjectName(domainName, containerName, interfaceType)));
} catch (MalformedObjectNameException e) {
LOGGER.error("Failed to build object name query: {}", e.getMessage(), e);
}
return result;
}
public static String getSystemServiceName(Class interfaceType) {
String name = interfaceType.getName();
name = name.substring(name.lastIndexOf('.') + 1);
if (name.endsWith("MBean")) {
name = name.substring(0, name.length() - 5);
}
return name;
}
public static ObjectName getContainerObjectName(String domainName, String containerName) {
String tmp = domainName + ":ContainerName=" + containerName + ",Type=JBIContainer";
ObjectName result = null;
try {
result = new ObjectName(tmp);
} catch (MalformedObjectNameException e) {
LOGGER.debug("Unable to build ObjectName", e);
} catch (NullPointerException e) {
LOGGER.debug("Unable to build ObjectName", e);
}
return result;
}
/**
* Register a System service
*
* @param service
* @param interfaceType
* @throws JBIException
*/
public void registerSystemService(BaseSystemService service, Class interfaceType) throws JBIException {
try {
String name = service.getName();
if (systemServices.containsKey(name)) {
throw new JBIException("A system service for the name " + name + " is already registered");
}
ObjectName objName = createObjectName(service);
LOGGER.debug("Registering system service: {}", objName);
ObjectName registeredName = registerMBean(objName, service, interfaceType, service.getDescription());
systemServices.put(name, registeredName);
} catch (MalformedObjectNameException e) {
throw new JBIException(e);
} catch (JMException e) {
throw new JBIException(e);
}
}
/**
* Unregister a System service
*
* @param service
* @throws JBIException
*/
public void unregisterSystemService(BaseSystemService service) throws JBIException {
String name = service.getName();
if (!systemServices.containsKey(name)) {
throw new JBIException("A system service for the name " + name + " is not registered");
}
ObjectName objName = systemServices.remove(name);
LOGGER.debug("Unregistering system service: {}", objName);
unregisterMBean(objName);
}
/**
* Unregister an MBean
*
* @param name
* @throws JBIException
*/
public void unregisterMBean(ObjectName name) throws JBIException {
try {
mbeanServerContext.unregisterMBean(name);
beanMap.remove(name);
} catch (JMException e) {
LOGGER.error("Failed to unregister mbean: {}", name, e);
throw new JBIException(e);
}
}
/**
* Unregister an MBean
*
* @param bean
* @throws JBIException
*/
public void unregisterMBean(Object bean) throws JBIException {
for (Iterator i = beanMap.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry) i.next();
if (entry.getValue() == bean) {
ObjectName name = (ObjectName) entry.getKey();
unregisterMBean(name);
break;
}
}
}
/**
* Get an array of MBeanOperationInfo
*
* @return array of OperationInfos
* @throws JMException
*/
public MBeanAttributeInfo[] getAttributeInfos() throws JMException {
AttributeInfoHelper helper = new AttributeInfoHelper();
helper.addAttribute(getObjectToManage(), "bindingComponents", "Get list of all binding components");
helper.addAttribute(getObjectToManage(), "engineComponents", "Get list of all engine components");
helper.addAttribute(getObjectToManage(), "pojoComponents", "Get list of all pojo components");
helper.addAttribute(getObjectToManage(), "systemInfo", "Return current version");
helper.addAttribute(getObjectToManage(), "systemServices", "Get list of system services");
return AttributeInfoHelper.join(super.getAttributeInfos(), helper.getAttributeInfos());
}
public MBeanOperationInfo[] getOperationInfos() throws JMException {
OperationInfoHelper helper = new OperationInfoHelper();
ParameterHelper ph = helper.addOperation(getObjectToManage(), "getComponentByName", 1, "look up Component by name");
ph.setDescription(0, "name", "Component name");
ph = helper.addOperation(getObjectToManage(), "getSystemService", 1, "look up System service by name");
ph.setDescription(0, "name", "System name");
ph = helper.addOperation(getObjectToManage(), "isBinding", 1, "Is Component a binding Component?");
ph.setDescription(0, "name", "Component name");
ph = helper.addOperation(getObjectToManage(), "isEngine", 1, "Is Component a service engine?");
ph.setDescription(0, "name", "Component name");
return OperationInfoHelper.join(super.getOperationInfos(), helper.getOperationInfos());
}
}