alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

JMeter example source code file (Functor.java)

This example JMeter source code file (Functor.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - JMeter tags/keywords

cannot, class, class, exception, functor, functor, illegalargumentexception, illegalstateexception, method, object, object, reflection, string, string, stringbuilder, util

The JMeter Functor.java source code

/*
 * 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.jorphan.reflect;

import java.lang.reflect.Method;
import java.util.Arrays;

import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JMeterError;
import org.apache.log.Logger;

/**
 * Implements function call-backs.
 *
 * Functors may be defined for instance objects or classes.
 *
 * The method is created on first use, which allows the invokee (class or instance)
 * to be omitted from the constructor.
 *
 * The class name takes precedence over the instance.
 *
 * If a functor is created with a particular instance, then that is used for all future calls;
 * if an object is provided, it is ignored.
 * This allows easy override of the table model behaviour.
 *
 * If an argument list is provided in the constructor, then that is ignored in subsequent invoke() calls.
 *
 * Usage:
 * f = new Functor("methodName")
 * o = f.invoke(object) - OR -
 * o = f.invoke(object,params)
 *
 * f2 = new Functor(object,"methodName");
 * o = f2.invoke() - OR -
 * o = f2.invoke(params)
 *
 * f3 = new Functor(class,"methodName");
 * o = f3.invoke(object) - will be ignored
 * o = f3.invoke() - OR -
 * o = f3.invoke(params)
 * o = f3.invoke(object,params) - object will be ignored
 *
 */
public class Functor {
    private static final Logger log = LoggingManager.getLoggerForClass();

    /*
     * If non-null, then any object provided to invoke() is ignored.
     */
    private final Object invokee;

    /*
     * Class to be used to create the Method.
     * Will be non-null if either Class or Object was provided during construction.
     *
     *  Can be used instead of invokee, e.g. when using interfaces.
    */
    private final Class<?> clazz;

    // Methondname must always be provided.
    private final String methodName;

    /*
     * If non-null, then any argument list passed to invoke() will be ignored.
     */
    private Object[] args;

    /*
     * Argument types used to create the method.
     * May be provided explicitly, or derived from the constructor argument list.
     */
    private final Class<?>[] types;

    /*
     * This depends on the class or invokee and either args or types;
     * it is set once by doCreateMethod(), which must be the only method to access it.
    */
    private Method methodToInvoke;

    Functor(){
        throw new IllegalArgumentException("Must provide at least one argument");
    }

    /**
     * Create a functor with the invokee and a method name.
     *
     * The invokee will be used in all future invoke calls.
     *
     * @param _invokee object on which to invoke the method
     * @param _methodName method name
     */
    public Functor(Object _invokee, String _methodName) {
        this(null, _invokee, _methodName, null, null);
    }

    /**
     * Create a functor from class and method name.
     * This is useful for methods defined in interfaces.
     *
     * The actual invokee must be provided in all invoke() calls,
     * and must be an instance of the class.
     *
     * @param _clazz class to be used
     * @param _methodName method name
     */
    public Functor(Class<?> _clazz, String _methodName) {
        this(_clazz, null, _methodName, null, null);
    }

    /**
     * Create a functor with the invokee, method name, and argument class types.
     *
     * The invokee will be ignored in any invoke() calls.
     *
     * @param _invokee object on which to invoke the method
     * @param _methodName method name
     * @param _types
     */
    public Functor(Object _invokee, String _methodName, Class<?>[] _types) {
        this(null, _invokee, _methodName, null, _types);
    }

    /**
     * Create a functor with the class, method name, and argument class types.
     *
     * Subsequent invoke() calls must provide the appropriate ivokee object.
     *
     * @param _clazz the class in which to find the method
     * @param _methodName method name
     * @param _types
     */
    public Functor(Class<?> _clazz, String _methodName, Class[] _types) {
        this(_clazz, null, _methodName, null, _types);
    }

    /**
     * Create a functor with just the method name.
     *
     * The invokee and any parameters must be provided in all invoke() calls.
     *
     * @param _methodName method name
     */
    public Functor(String _methodName) {
        this(null, null, _methodName, null, null);
    }

    /**
     * Create a functor with the method name and argument class types.
     *
     * The invokee must be provided in all invoke() calls
     *
     * @param _methodName method name
     * @param _types parameter types
     */
    public Functor(String _methodName, Class<?>[] _types) {
        this(null, null, _methodName, null, _types);
    }

    /**
     * Create a functor with an invokee, method name, and argument values.
     *
     * The invokee will be ignored in any invoke() calls.
     *
     * @param _invokee object on which to invoke the method
     * @param _methodName method name
     * @param _args arguments to be passed to the method
     */
    public Functor(Object _invokee, String _methodName, Object[] _args) {
        this(null, _invokee, _methodName, _args, null);
    }

    /**
     * Create a functor from method name and arguments.
     *
     * The class will be determined from the first invoke call.
     * All invoke calls must include a target object;
     * which must be of the same type as the initial invokee.
     *
     * @param _methodName method name
     * @param _args
     */
    public Functor(String _methodName, Object[] _args) {
        this(null, null, _methodName, _args, null);
    }

    /**
     * Create a functor from various different combinations of parameters.
     *
     * @param _clazz class containing the method
     * @param _invokee invokee to use for the method call
     * @param _methodName the method name (required)
     * @param _args arguments to be used
     * @param _types types of arguments to be used
     *
     * @throws IllegalArgumentException if:
     * - methodName is null
     * - both class and invokee are specified
     * - both arguments and types are specified
     */
    private Functor(Class<?> _clazz, Object _invokee, String _methodName, Object[] _args, Class[] _types) {
        if (_methodName == null){
            throw new IllegalArgumentException("Methodname must not be null");
        }
        if (_clazz != null && _invokee != null){
            throw new IllegalArgumentException("Cannot provide both Class and Object");
        }
        if (_args != null && _types != null){
            throw new IllegalArgumentException("Cannot provide both arguments and argument types");
        }
        // If class not provided, default to invokee class, else null
        this.clazz = _clazz != null ? _clazz : (_invokee != null ? _invokee.getClass() : null);
        this.invokee = _invokee;
        this.methodName = _methodName;
        this.args = _args;
        // If types not provided, default to argument types, else null
        this.types = _types != null ? _types : (_args != null ? _getTypes(_args) : null);
    }

    //////////////////////////////////////////

    /*
     * Low level invocation routine.
     *
     * Should only be called after any defaults have been applied.
     *
     */
    private Object doInvoke(Class<?> _class, Object _invokee, Object[] _args) {
        Class<?>[] argTypes = getTypes(_args);
        try {
            Method method = doCreateMethod(_class , argTypes);
            if (method == null){
                final String message = "Can't find method "
                    +_class.getName()+"#"+methodName+typesToString(argTypes);
                log.error(message, new Throwable());
                throw new JMeterError(message);
            }
            return method.invoke(_invokee, _args);
        } catch (Exception e) {
            final String message = "Trouble functing: "
                +_class.getName()
                +"."+methodName+"(...) : "
                +" invokee: "+_invokee
                +" "+e.getMessage();
            log.warn(message, e);
            throw new JMeterError(message,e);
        }
    }

    /**
     * Invoke a Functor, which must have been created with either a class name or object.
     *
     * @return the object if any
     */
    public Object invoke() {
        if (invokee == null) {
            throw new IllegalStateException("Cannot call invoke() - invokee not known");
        }
        // If invokee was provided, then clazz has been set up
        return doInvoke(clazz, invokee, getArgs());
    }

    /**
     * Invoke the method on a given object.
     *
     * @param p_invokee - provides the object to call; ignored if the class or object were provided to the constructor
     * @return the value
     */
    public Object invoke(Object p_invokee) {
        return invoke(p_invokee, getArgs());
    }

    /**
     * Invoke the method with the provided parameters.
     *
     * The invokee must have been provided in the constructor.
     *
     * @param p_args parameters for the method
     * @return the value
     */
    public Object invoke(Object[] p_args) {
        if (invokee == null){
            throw new IllegalStateException("Invokee was not provided in constructor");
        }
        // If invokee was provided, then clazz has been set up
        return doInvoke(clazz, invokee, args != null? args : p_args);
    }

    /**
     * Invoke the method on the invokee with the provided parameters.
     *
     * The invokee must agree with the class (if any) provided at construction time.
     *
     * If the invokee was provided at construction time, then this invokee will be ignored.
     * If actual arguments were provided at construction time, then arguments will be ignored.
     *
     */
    public Object invoke(Object p_invokee, Object[] p_args) {
        return doInvoke(clazz != null ? clazz : p_invokee.getClass(), // Use constructor class if present
                       invokee != null ? invokee : p_invokee, // use invokee if provided
                        args != null? args : p_args);// use argumenrs if provided
    }

    /*
     * Low-level (recursive) routine to define the method - if not already defined.
     * Synchronized to protect access to methodToInvoke.
     */
    private synchronized Method doCreateMethod(Class<?> p_class, Class[] p_types) {
        if (log.isDebugEnabled()){
            log.debug("doCreateMethod() using "+this.toString()
                +"class="
                + p_class.getName()
                + " types: " + Arrays.asList(p_types));
        }
        if (methodToInvoke == null) {
            try {
                methodToInvoke = p_class.getMethod(methodName, p_types);
            } catch (Exception e) {
                for (int i = 0; i < p_types.length; i++) {
                    Class<?> primitive = getPrimitive(p_types[i]);
                    if (primitive != null) {
                        methodToInvoke = doCreateMethod(p_class, getNewArray(i, primitive, p_types));
                        if (methodToInvoke != null) {
                            return methodToInvoke;
                        }
                    }
                    Class<?>[] interfaces = p_types[i].getInterfaces();
                    for (int j = 0; j < interfaces.length; j++) {
                        methodToInvoke = doCreateMethod(p_class,getNewArray(i, interfaces[j], p_types));
                        if (methodToInvoke != null) {
                            return methodToInvoke;
                        }
                    }
                    Class<?> parent = p_types[i].getSuperclass();
                    if (parent != null) {
                        methodToInvoke = doCreateMethod(p_class,getNewArray(i, parent, p_types));
                        if (methodToInvoke != null) {
                            return methodToInvoke;
                        }
                    }
                }
            }
        }
        return methodToInvoke;
    }

    /**
     * Check if a read Functor method is valid.
     *
     * @deprecated ** for use by Unit test code only **
     *
     * @return true if method exists
     */
    @Deprecated
    public boolean checkMethod(Object _invokee){
        Method m = null;
        try {
            m = doCreateMethod(_invokee.getClass(), getTypes(args));
        } catch (Exception e){
            // ignored
        }
        return null != m;
    }

    /**
     * Check if a write Functor method is valid.
     *
     * @deprecated ** for use by Unit test code only **
     *
     * @return true if method exists
     */
    @Deprecated
    public boolean checkMethod(Object _invokee, Class<?> c){
        Method m = null;
        try {
            m = doCreateMethod(_invokee.getClass(), new Class[]{c});
        } catch (Exception e){
            // ignored
        }
        return null != m;
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder(100);
        if (clazz != null){
            sb.append(clazz.getName());
        }
        if (invokee != null){
            sb.append("@");
            sb.append(System.identityHashCode(invokee));
        }
        sb.append(".");
        sb.append(methodName);
        typesToString(sb,types);
        return sb.toString();
    }

    private void typesToString(StringBuilder sb,Class<?>[] _types) {
        sb.append("(");
        if (_types != null){
            for(int i=0; i < _types.length; i++){
                if (i>0) {
                    sb.append(",");
                }
                sb.append(_types[i].getName());
            }
        }
        sb.append(")");
    }

    private String typesToString(Class<?>[] argTypes) {
        StringBuilder sb = new StringBuilder();
        typesToString(sb,argTypes);
        return sb.toString();
    }

    private Class<?> getPrimitive(Class t) {
        if (t==null) {
            return null;
        }
        if (t.equals(Integer.class)) {
            return int.class;
        } else if (t.equals(Long.class)) {
            return long.class;
        } else if (t.equals(Double.class)) {
            return double.class;
        } else if (t.equals(Float.class)) {
            return float.class;
        } else if (t.equals(Byte.class)) {
            return byte.class;
        } else if (t.equals(Boolean.class)) {
            return boolean.class;
        } else if (t.equals(Short.class)) {
            return short.class;
        } else if (t.equals(Character.class)) {
            return char.class;
        }
        return null;
    }

    private Class<?>[] getNewArray(int i, Class replacement, Class[] orig) {
        Class<?>[] newArray = new Class[orig.length];
        for (int j = 0; j < newArray.length; j++) {
            if (j == i) {
                newArray[j] = replacement;
            } else {
                newArray[j] = orig[j];
            }
        }
        return newArray;
    }

    private Class<?>[] getTypes(Object[] _args) {
        if (types == null)
        {
            return _getTypes(_args);
        }
        return types;
    }

    private static Class<?>[] _getTypes(Object[] _args) {
        Class<?>[] _types;
        if (_args != null) {
            _types = new Class[_args.length];
            for (int i = 0; i < _args.length; i++) {
                _types[i] = _args[i].getClass();
            }
        } else {
            _types = new Class[0];
        }
        return _types;
    }

    private Object[] getArgs() {
        if (args == null) {
            args = new Object[0];
        }
        return args;
    }
}

Other JMeter examples (source code examples)

Here is a short list of links related to this JMeter Functor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.