All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cyclopsgroup.jmxterm.cmd.RunCommand Maven / Gradle / Ivy

There is a newer version: 1.0.4
Show newest version
package org.cyclopsgroup.jmxterm.cmd;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.management.JMException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

import org.apache.commons.lang.Validate;
import org.cyclopsgroup.jcli.annotation.Argument;
import org.cyclopsgroup.jcli.annotation.Cli;
import org.cyclopsgroup.jcli.annotation.MultiValue;
import org.cyclopsgroup.jcli.annotation.Option;
import org.cyclopsgroup.jmxterm.Command;
import org.cyclopsgroup.jmxterm.Session;
import org.cyclopsgroup.jmxterm.SyntaxUtils;
import org.cyclopsgroup.jmxterm.io.ValueOutputFormat;
import org.cyclopsgroup.jmxterm.utils.ValueFormat;

/**
 * Command to run an MBean operation
 *
 * @author Jiaqi Guo
 */
@Cli( name = "run", description = "Invoke an MBean operation", note = "Syntax is \n run  [parameter1] [parameter2]" )
public class RunCommand
    extends Command
{
    private String bean;

    private String domain;

    private boolean measure;

    private List parameters = Collections.emptyList();

    private boolean showQuotationMarks;

    private String types;

    /**
     * @inheritDoc
     */
    @Override
    public List doSuggestArgument()
        throws IOException, JMException
    {
        Session session = getSession();
        if ( getSession().getBean() != null )
        {
            MBeanInfo info =
                session.getConnection().getServerConnection().getMBeanInfo( new ObjectName(
                                                                                            session.getBean() ) );
            MBeanOperationInfo[] operationInfos = info.getOperations();
            List ops = new ArrayList( operationInfos.length );
            for ( MBeanOperationInfo op : operationInfos )
            {
                ops.add( op.getName() );
            }
            return ops;
        }
        return null;
    }

    /**
     * @inheritDoc
     */
    @Override
    public void execute()
        throws MalformedObjectNameException, IOException, JMException
    {
        Session session = getSession();
        String beanName = BeanCommand.getBeanName( bean, domain, session );
        if ( beanName == null )
        {
            throw new IllegalArgumentException(
                                                "Please specify MBean to invoke either using -b option or bean command" );
        }

        Validate.isTrue( parameters.size() > 0,
                         "At least one parameter is needed" );
        String[] paramTypes = null;
        if ( types != null )
        {
            paramTypes = types.split( "," );
            Validate.isTrue( paramTypes.length == parameters.size() - 1,
                             "Signature does not match parameter count" );
        }
        String operationName = parameters.get( 0 );
        ObjectName name = new ObjectName( beanName );
        MBeanServerConnection con =
            session.getConnection().getServerConnection();
        MBeanInfo beanInfo = con.getMBeanInfo( name );

        // Looking for operation to invoke
        MBeanOperationInfo operationInfo = null;
        for ( MBeanOperationInfo info : beanInfo.getOperations() )
        {
            if ( operationName.equals( info.getName() )
                && info.getSignature().length == parameters.size() - 1 )
            {
                // If operation name and number of parameters matches, optionally check parameter types
                if ( paramTypes == null )
                {
                    operationInfo = info;
                    break;
                }
                // If paramTypes parameter is set, narrow down operation with parameter matching
                boolean match = true;
                MBeanParameterInfo[] paramInfos = info.getSignature();
                for ( int i = 0; i < paramTypes.length && i < paramInfos.length; i++ )
                {
                    // String type is treated specially
                    // type "string" implies type "java.lang.String"
                    if ( paramInfos[i].getType().equals( String.class.getName() )
                        && paramTypes[i].equals( "string" ) )
                    {
                        continue;
                    }
                    if ( !paramTypes[i].equals( paramInfos[i].getType() ) )
                    {
                        match = false;
                        break;
                    }
                }
                if ( match )
                {
                    operationInfo = info;
                    break;
                }
            }
        }
        // If no matching operation is found, throw an exception
        if ( operationInfo == null )
        {
            throw new IllegalArgumentException( "Operation " + operationName
                + " with " + ( parameters.size() - 1 )
                + " parameters doesn't exist in bean " + beanName );
        }

        // Now set parameters to invoke with
        Object[] params = new Object[parameters.size() - 1];
        MBeanParameterInfo[] paramInfos = operationInfo.getSignature();
        Validate.isTrue( params.length == paramInfos.length,
                         String.format( "%d parameters are expected but %d are provided",
                                        paramInfos.length, params.length ) );
        String[] signatures = new String[paramInfos.length];
        for ( int i = 0; i < paramInfos.length; i++ )
        {
            MBeanParameterInfo paramInfo = paramInfos[i];
            String expression = parameters.get( i + 1 );
            if ( expression != null )
            {
                expression = ValueFormat.parseValue( expression );
            }
            Object paramValue =
                SyntaxUtils.parse( expression, paramInfo.getType() );
            params[i] = paramValue;
            signatures[i] = paramInfo.getType();
        }
        session.output.printMessage( String.format( "calling operation %s of mbean %s with params %s",
                operationName, beanName, Arrays.toString(params) ) );


        // Invoke operation, record execution time if measure flag is on
        Object result;
        if ( measure )
        {
            long start = System.currentTimeMillis();
            try
            {
                result = con.invoke( name, operationName, params, signatures );
            }
            finally
            {
                long latency = System.currentTimeMillis() - start;
                session.output.printMessage( latency
                    + "ms is taken by invocation" );
            }
        }
        else
        {
            result = con.invoke( name, operationName, params, signatures );
        }
        session.output.printMessage( "operation returns: " );
        new ValueOutputFormat( 2, false, showQuotationMarks ).printValue( session.output,
                                                                          result );
        // Finish with an empty line
        session.output.println( "" );
    }

    /**
     * @param bean Bean under which the operation is
     */
    @Option( name = "b", longName = "bean", description = "MBean to invoke" )
    public final void setBean( String bean )
    {
        this.bean = bean;
    }

    /**
     * @param domain Domain under which is bean is
     */
    @Option( name = "d", longName = "domain", description = "Domain of MBean to invoke" )
    public final void setDomain( String domain )
    {
        this.domain = domain;
    }

    /**
     * @param measure True if you want to display latency
     */
    @Option( name = "m", longName = "measure", description = "Measure the time spent on the invocation of operation" )
    public final void setMeasure( boolean measure )
    {
        this.measure = measure;
    }

    /**
     * @param types
     */
    @Option( name = "t", longName = "types", description = "Require parameters to have specific types (comma separated)" )
    public final void setTypes( String types )
    {
        this.types = types;
    }

    /**
     * @param parameters List of parameters. The first parameter is operation name
     */
    @MultiValue( listType = ArrayList.class, minValues = 1 )
    @Argument( description = "The first parameter is operation name, which is followed by list of arguments" )
    public final void setParameters( List parameters )
    {
        Validate.notNull( parameters, "Parameters can't be NULL" );
        this.parameters = parameters;
    }

    /**
     * @param showQuotationMarks True if output is surrounded by quotation marks
     */
    @Option( name = "q", longName = "quots", description = "Flag for quotation marks" )
    public final void setShowQuotationMarks( boolean showQuotationMarks )
    {
        this.showQuotationMarks = showQuotationMarks;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy