com.qmetry.qaf.automation.step.JavaStep.java Source code

Java tutorial

Introduction

Here is the source code for com.qmetry.qaf.automation.step.JavaStep.java

Source

/*******************************************************************************
 * QMetry Automation Framework provides a powerful and versatile platform to
 * author
 * Automated Test Cases in Behavior Driven, Keyword Driven or Code Driven
 * approach
 * Copyright 2016 Infostretch Corporation
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE
 * You should have received a copy of the GNU General Public License along with
 * this program in the name of LICENSE.txt in the root folder of the
 * distribution. If not, see https://opensource.org/licenses/gpl-3.0.html
 * See the NOTICE.TXT file in root folder of this source files distribution
 * for additional information regarding copyright ownership and licenses
 * of other open source software / files used by QMetry Automation Framework.
 * For any inquiry or need additional information, please contact
 * support-qaf@infostretch.com
 *******************************************************************************/

package com.qmetry.qaf.automation.step;

import static com.qmetry.qaf.automation.core.ConfigurationManager.getBundle;
import static com.qmetry.qaf.automation.util.ClassUtil.getAnnotation;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.apache.commons.lang.StringUtils.isNotBlank;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlRootElement;

import org.apache.commons.lang.text.StrSubstitutor;
import org.json.JSONException;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.qmetry.qaf.automation.core.TestBaseProvider;
import com.qmetry.qaf.automation.data.MetaData;
import com.qmetry.qaf.automation.ui.api.TestPage;
import com.qmetry.qaf.automation.ui.webdriver.QAFWebElement;
import com.qmetry.qaf.automation.util.JSONUtil;

/**
 * com.qmetry.qaf.automation.step.JavaStep.java
 * 
 * @author chirag.jayswal
 */
@XmlRootElement
public class JavaStep extends BaseTestStep {
    /**
     * For internal use only.
     */
    public static final String ATTACH_LISTENER = "attach.javastep.listener";
    protected transient Method method;
    private Object stepProvider;
    // package access
    String signature = "";
    private boolean qafStepImpl = true;

    public JavaStep(Method method) {
        this(method, "", "");
    }

    public JavaStep(Method method, String name, String description) {
        this.method = method;
        this.name = name;
        this.description = description;
        init();
    }

    public boolean isQafStepImpl() {
        return qafStepImpl;
    }

    private void init() {
        fileName = method.getDeclaringClass().getName();
        MetaData stepMetaData = getAnnotation(method, MetaData.class);
        MetaData classMetaData = getAnnotation(method.getDeclaringClass(), MetaData.class);
        QAFTestStep step = getAnnotation(method, QAFTestStep.class);

        if (null != classMetaData && isNotBlank(classMetaData.value())) {
            try {
                metaData = JSONUtil.toMap(classMetaData.value());
            } catch (JSONException e) {
                System.err.println(metaData + " is not valid json map for step meta-data");
            }
        }

        setMetaData();
        if (null != stepMetaData && isNotBlank(stepMetaData.value())) {
            try {
                // keep class meta-data which is not in step meta-data, override
                // common
                metaData.putAll(JSONUtil.toMap(stepMetaData.value()));
            } catch (JSONException e) {
                System.err.println(metaData + " is not valid json map for step meta-data");
            }
        }

        if (isBlank(name)) {
            QAFTestStepProvider provider = method.getDeclaringClass().getAnnotation(QAFTestStepProvider.class);

            String prefix = (provider != null) && isNotBlank(provider.prefix()) ? provider.prefix() + "." : "";
            name = prefix + ((step != null) && isNotBlank(step.stepName()) ? step.stepName() : method.getName());

        }
        if (step != null) {
            threshold = step.threshold();
            if (isNotBlank(step.description())) {
                // highest priority to QAFTestStep annotation if multiple step
                // definition way opted
                description = step.description();
                qafStepImpl = true;
            }
        }
        if (isBlank(description)) {
            description = name;
        }

    }

    /*
     * (non-Javadoc)
     * @see com.qmetry.qaf.automation.step.TestStep#execute(java.lang.Object[])
     */
    @Override
    protected Object doExecute() {
        try {
            Object stepProvider = getStepProvider();
            // block joint-point listener
            TestBaseProvider.instance().get().getContext().setProperty(ATTACH_LISTENER, false);
            TestBaseProvider.instance().get().getContext().setProperty("current.teststep", this);
            method.setAccessible(true);
            return method.invoke(stepProvider, processArgs(method, actualArgs));
        } catch (IllegalArgumentException e) {
            throw new StepInvocationException(this, "Unable to invoke JavaStep with given arguments: " + getName()
                    + Arrays.toString(actualArgs) + "\nat " + getSignature(), true);

        } catch (IllegalAccessException e) {
            throw new StepInvocationException(this, "Unable to invoke JavaStep: " + getName()
                    + Arrays.toString(actualArgs) + "\nat " + getSignature(), true);

        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof Error) {
                throw (Error) e.getCause();
            }
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new StepInvocationException(this, e.getCause());
        } catch (InstantiationException e) {
            throw new StepInvocationException(this,
                    "Unable to Instantiate JavaStep: " + getName() + Arrays.toString(actualArgs) + getSignature(),
                    true);
        }
    }

    protected Object getStepProvider() throws InstantiationException, IllegalAccessException {

        return stepProvider == null ? getClassInstance() : stepProvider;
    }

    /**
     * @return the method
     */
    public Method getMethod() {
        return method;
    }

    @Override
    public String getSignature() {
        return signature;
    }

    protected Object[] processArgs(Method method, Object... objects) {
        int noOfParams = method.getParameterTypes().length;
        if (noOfParams == 0) {
            return null;
        }
        Object[] params = new Object[noOfParams];
        Map<String, Object> context = getStepExecutionTracker().getContext();

        try {
            if ((noOfParams == (objects.length - 1)) && method.getParameterTypes()[noOfParams - 1].isArray()) {
                // case of optional arguments!...
                System.arraycopy(objects, 0, params, 0, objects.length);
                params[noOfParams - 1] = "[]";
            } else {
                System.arraycopy(objects, 0, params, 0, noOfParams);
            }
        } catch (Exception e) {
            throw new RuntimeException("Wrong number of parameters, Expected " + noOfParams
                    + " parameters but Actual is " + (objects == null ? "0" : objects.length));
        }
        Gson gson = new GsonBuilder().setDateFormat("dd-MM-yyyy").create();
        description = StrSubstitutor.replace(description, context);
        description = getBundle().getSubstitutor().replace(description);
        for (int i = 0; i < noOfParams; i++) {

            if ((params[i] instanceof String)) {
                String pstr = (String) params[i];

                if (pstr.startsWith("${") && pstr.endsWith("}")) {
                    String pname = pstr.substring(2, pstr.length() - 1);
                    params[i] = context.containsKey(pstr) ? context.get(pstr)
                            : context.containsKey(pname) ? context.get(pname)
                                    : getBundle().containsKey(pstr) ? getBundle().getObject(pstr)
                                            : getBundle().getObject(pname);
                } else if (pstr.indexOf("$") >= 0) {
                    pstr = getBundle().getSubstitutor().replace(pstr);
                    params[i] = StrSubstitutor.replace(pstr, context);
                }

            }
            Class<?> paramType = method.getParameterTypes()[i];
            if (String.class.isAssignableFrom(paramType)) {
                continue;
            }
            try {
                String strVal = gson.toJson(params[i]);
                if (params[i] instanceof String) {
                    strVal = String.valueOf(params[i]);
                }

                strVal = getBundle().getSubstitutor().replace(strVal);
                strVal = StrSubstitutor.replace(strVal, context);
                Object o = gson.fromJson(strVal, paramType);
                params[i] = o;
            } catch (Exception e) {
            }
        }

        return params;
    }

    @Override
    public TestStep clone() {
        JavaStep cloneObj = new JavaStep(method);
        if (null != actualArgs) {
            cloneObj.actualArgs = actualArgs.clone();
        }
        return cloneObj;
    }

    public void getSubSteps() {
        if (method.getReturnType().isInstance(QAFWebElement.class)) {

        }
    }

    private Object getClassInstance() throws InstantiationException, IllegalAccessException {
        Class<?> cls = method.getDeclaringClass();
        if (getBundle().getBoolean("step.provider.sharedinstance", false) && isSharableInstance(cls)) {
            // allow class variable sharing among steps
            Object obj = getBundle().getObject(cls.getName());
            if (null == obj) {
                obj = cls.newInstance();
                getBundle().setProperty(cls.getName(), obj);
            }
            return obj;
        }
        return cls.newInstance();
    }

    private boolean isSharableInstance(Class<?> cls) {

        if (TestPage.class.isAssignableFrom(cls) || QAFWebElement.class.isAssignableFrom(cls)) {
            return false;
        }
        return true;
    }

    private void setMetaData() {

        Annotation[] allAnnotations = method.getAnnotations();
        for (Annotation annotation : allAnnotations) {
            if (annotation instanceof MetaData || annotation instanceof QAFTestStep)
                continue;

            Method[] annotationMethods = annotation.annotationType().getDeclaredMethods();
            for (Method annotationMethod : annotationMethods) {
                Object objVal;
                try {
                    objVal = annotationMethod.invoke(annotation);
                    String key = annotationMethod.getName();
                    metaData.put(key, objVal);
                    if (key.equalsIgnoreCase("value") && isTestStepAnnotation(annotation)) {
                        description = (String) objVal;
                        qafStepImpl = false;

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    private boolean isTestStepAnnotation(Annotation annotation) {
        List<String> annotationPkgs = getBundle().getList("step.annotation.pkgs",
                Arrays.asList("cucumber.api.java"));

        for (String pkg : annotationPkgs) {
            if (annotation.annotationType().getName().indexOf(pkg) >= 0) {
                return true;
            }
        }
        return false;
    }
}