Package org.qzerver.model.agent.action.providers.executor.jmx

Source Code of org.qzerver.model.agent.action.providers.executor.jmx.JmxActionExecutor

package org.qzerver.model.agent.action.providers.executor.jmx;

import com.gainmatrix.lib.spring.validation.BeanValidationUtils;
import com.google.common.base.Preconditions;
import org.qzerver.model.agent.action.providers.ActionDefinition;
import org.qzerver.model.agent.action.providers.ActionExecutor;
import org.qzerver.model.agent.action.providers.ActionPlaceholders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.util.ClassUtils;
import org.springframework.validation.Validator;

import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JmxActionExecutor implements ActionExecutor {

    private static final Logger LOGGER = LoggerFactory.getLogger(JmxActionExecutor.class);

    private Validator beanValidator;

    @Override
    public JmxActionResult execute(ActionDefinition actionDefinition,
        long scheduleExecutionId, String nodeAddress)
    {
        Preconditions.checkNotNull(actionDefinition, "Definition is null");
        Preconditions.checkNotNull(nodeAddress, "Node is not specified");

        BeanValidationUtils.checkValidity(actionDefinition, beanValidator);

        JmxActionDefinition definition = (JmxActionDefinition) actionDefinition;

        LOGGER.debug("Execute jmx call action on node [{}]", nodeAddress);

        String effectiveUrl = definition.getUrl();
        effectiveUrl = ActionPlaceholders.substituteNode(effectiveUrl, nodeAddress);
        effectiveUrl = ActionPlaceholders.substituteExecution(effectiveUrl, scheduleExecutionId);

        try {
            JMXServiceURL jmxUrl = new JMXServiceURL(effectiveUrl);

            return processJmxUrl(jmxUrl, definition);
        } catch (Exception e) {
            LOGGER.debug("Fail to execute jmx call", e);
            return produceExceptionalResult(e);
        }
    }

    private JmxActionResult produceExceptionalResult(Exception e) {
        JmxActionResult result = new JmxActionResult();
        result.setExceptionClass(e.getClass().getCanonicalName());
        result.setExceptionMessage(e.getLocalizedMessage());
        result.setStatus(JmxActionResultStatus.EXCEPTION);
        result.setResult(null);

        return result;
    }

    private JmxActionResult processJmxUrl(JMXServiceURL jmxUrl, JmxActionDefinition definition)
        throws Exception
    {
        Map<String, Object> environment = new HashMap<String, Object>();

        if (definition.getUsername() != null) {
            String[] credentials = new String[] {
                definition.getUsername(),
                definition.getPassword()
            };
            environment.put(JMXConnector.CREDENTIALS, credentials);
        }

        JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(jmxUrl, environment);
        jmxConnector.connect(environment);

        try {
            return processJmxConnector(jmxConnector, definition);
        } finally {
            jmxConnector.close();
        }
    }

    private JmxActionResult processJmxConnector(JMXConnector jmxConnector, JmxActionDefinition definition)
        throws Exception
    {
        MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();

        List<String> callParameters = definition.getParameters();
        String callBean = definition.getBean();
        String callMethod = definition.getMethod();

        ObjectName objectName = new ObjectName(callBean);

        // Find MBean
        MBeanInfo mBeanInfo = mBeanServerConnection.getMBeanInfo(objectName);
        if (mBeanInfo == null) {
            throw new IllegalArgumentException("MBean with name " + callBean + " is not found");
        }

        // Find operation
        MBeanOperationInfo mBeanOperationInfo = findMBeanOperation(mBeanInfo, definition.getMethod());
        if (mBeanOperationInfo == null) {
            throw new IllegalArgumentException("Operation [" + callMethod + "] is not found for bean " + callBean);
        }

        // Get arguments type
        MBeanParameterInfo[] mBeanParameterInfos = mBeanOperationInfo.getSignature();

        int realCount = (mBeanParameterInfos != null) ? mBeanParameterInfos.length : 0;
        int haveCount = (callParameters != null) ? callParameters.size() : 0;

        if (realCount != haveCount) {
            throw new IllegalArgumentException("Method " + callMethod + " of bean " + callBean +
                " has " + realCount + " arguments but there are " + haveCount + " values specified");
        }

        // Compose parameters
        Object[] parameterArray = null;
        String[] signatureArray = null;

        if ((callParameters != null) && (mBeanParameterInfos != null) && (realCount > 0)) {
            parameterArray = new Object[realCount];
            signatureArray = new String[realCount];

            SimpleTypeConverter typeConverter = new SimpleTypeConverter();

            for (int i = 0; i < realCount; i++) {
                String value = callParameters.get(i);

                String requiredType = mBeanParameterInfos[i].getType();
                Class<?> requiredClass = ClassUtils.forName(requiredType, this.getClass().getClassLoader());

                parameterArray[i] = typeConverter.convertIfNecessary(value, requiredClass);
                signatureArray[i] = requiredType;
            }
        }

        // Make call
        Object resultObject = mBeanServerConnection.invoke(objectName, mBeanOperationInfo.getName(),
            parameterArray, signatureArray);

        // Convert object to text
        String resultText = String.valueOf(resultObject);

        // Compose result
        JmxActionResult result = new JmxActionResult();
        result.setResult(resultText);
        result.setStatus(JmxActionResultStatus.CALLED);

        return result;
    }

    private static MBeanOperationInfo findMBeanOperation(MBeanInfo mBeanInfo, String method) {
        MBeanOperationInfo[] mBeanOperationInfos = mBeanInfo.getOperations();

        for (MBeanOperationInfo mBeanOperationInfo : mBeanOperationInfos) {
            String operationName = mBeanOperationInfo.getName();

            // Compare short names
            if (method.equals(operationName)) {
                return mBeanOperationInfo;
            }

            // Compare fully qualified names
            MBeanParameterInfo[] mBeanParameterInfos = mBeanOperationInfo.getSignature();
            if (mBeanParameterInfos == null) {
                continue;
            }

            StringBuilder sb = new StringBuilder();
            for (MBeanParameterInfo mBeanParameterInfo : mBeanParameterInfos) {
                if (sb.length() > 0) {
                    sb.append(",");
                }
                sb.append(mBeanParameterInfo.getType());
            }

            String operationSignature = String.format("%s(%s)", operationName, sb.toString());
            if (method.equals(operationSignature)) {
                return mBeanOperationInfo;
            }
        }

        return null;
    }

    @Required
    public void setBeanValidator(Validator beanValidator) {
        this.beanValidator = beanValidator;
    }
}
TOP

Related Classes of org.qzerver.model.agent.action.providers.executor.jmx.JmxActionExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.