com.intuit.tank.harness.functions.StringFunctions.java Source code

Java tutorial

Introduction

Here is the source code for com.intuit.tank.harness.functions.StringFunctions.java

Source

package com.intuit.tank.harness.functions;

/*
 * #%L
 * Intuit Tank Agent (apiharness)
 * %%
 * Copyright (C) 2011 - 2015 Intuit Inc.
 * %%
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * #L%
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Random;
import java.util.Stack;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.intuit.tank.harness.APITestHarness;
import com.intuit.tank.harness.logging.LogUtil;
import com.intuit.tank.harness.test.data.Variables;
import com.intuit.tank.logging.LogEventType;
import com.intuit.tank.vm.common.util.ValidationUtil;

/**
 * 
 * StringFunctions functions useful for String info. Functions start with #function and use dot notation to pass
 * parameters. The first parameter is the class of function. string in this case. The next value is the function name
 * Valid values are:
 * <ul>
 * <li>userid - @see {@link StringFunctions#userIdDate(int, String)}</li>
 * <li>alphalower - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphaupper - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixed - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>numeric - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>special - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>unicode - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixednumeric - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixedspecial - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixedunicode - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixednumericspecial - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>alphamixednumericspecialunicode - @see {@link StringFunctions#randomString(String[], int)}</li>
 * <li>concat - @see {@link StringFunctions#concat(String[], Variables)}</li>
 * <li>useridFromRange - @see {@link StringFunctions#userIdFromRange(String[])}</li>
 * <li>substring - @see {@link StringFunctions#getSubstring(String, int, int)}</li>
 * </ul>
 * 
 * 
 * @author dangleton
 * 
 */
class StringFunctions {

    private static final Logger LOG = Logger.getLogger(StringFunctions.class);

    /**
     * Preset values
     */
    static final String[] alphaUpper = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
            "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
    static final String[] alphaLower = { "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
            "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
    static final String[] numeric = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
    static final String[] special = { "!", "@", "#", "$", "%", "^", "*", "{", "[", "}", "]", ":", ";", ",", ".",
            "?", "~", "`" };
    static final String[] unicode = { "\u00a1", "\u00a2", "\u00a3", "\u00a4", "\u00a5", "\u00A9", "\u00ae",
            "\u00bc", "\u00bd", "\u00be", "\u00bf", "\u00e0", "\u00e1", "\u00e2", "\u00e3", "\u00e4", "\u00e5",
            "\u00e6" };

    static Random rnd = new Random();
    static private Hashtable<String, Stack<Integer>> stackMap = new Hashtable<String, Stack<Integer>>();

    /**
     * Is this a valid String function request
     * 
     * @param values
     *            The command
     * @return TRUE if valid format; FALSE otherwise
     */
    static public boolean isValid(String[] values) {
        try {
            if (values[3] == "")
                return false;
            if (values[2].equalsIgnoreCase("userid") || values[2].equalsIgnoreCase("randomalphalower")
                    || values[2].equalsIgnoreCase("randomalphaupper")
                    || values[2].equalsIgnoreCase("randomalphamixed") || values[2].equalsIgnoreCase("randomnumeric")
                    || values[2].equalsIgnoreCase("randomspecial")
                    || values[2].equalsIgnoreCase("randomalphamixednumeric")
                    || values[2].equalsIgnoreCase("randomalphamixedspecial")
                    || values[2].equalsIgnoreCase("randomalphamixednumericspecial")
                    || values[2].equalsIgnoreCase("concat") || values[2].equalsIgnoreCase("useridFromRange")
                    || values[2].equalsIgnoreCase("useridFromRangeExclude")
                    || values[2].equalsIgnoreCase("useridFromRangeInclude")
                    || values[2].equalsIgnoreCase("useridFromRangeWithMod")
                    || values[2].equalsIgnoreCase("useridFromRangeWithModExclude")
                    || values[2].equalsIgnoreCase("useridFromRangeWithModInclude")
                    || values[2].equalsIgnoreCase("substring"))
                return true;
            return false;
        } catch (Exception ex) {
            return false;
        }
    }

    /**
     * Process the numeric request
     * 
     * @param values
     *            The command line
     * @return The requested value; "" if there was an error
     */
    static public String executeFunction(String[] values, Variables variables, String addtlString) {
        try {
            if (values[2].equalsIgnoreCase("userid")) {
                return StringFunctions.userIdDate(Integer.valueOf(values[3]), values[4]);
            } else if (values[2].equalsIgnoreCase("randomalphalower")) {
                return StringFunctions.randomString(StringFunctions.alphaLower, Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomalphaupper")) {
                return StringFunctions.randomString(StringFunctions.alphaUpper, Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomalphamixed")) {
                return StringFunctions.randomString(StringFunctions.alphaMixed(), Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomnumeric")) {
                return StringFunctions.randomString(StringFunctions.numeric, Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomspecial")) {
                return StringFunctions.randomString(StringFunctions.special, Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomalphamixednumeric")) {
                return StringFunctions.randomString(StringFunctions.alphaMixedNumeric(),
                        Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomalphamixedspecial")) {
                return StringFunctions.randomString(StringFunctions.alphaMixedSpecial(),
                        Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("randomalphaMixedNumericSpecial")) {
                return StringFunctions.randomString(StringFunctions.alphaMixedNumericSpecial(),
                        Integer.valueOf(values[3]));
            } else if (values[2].equalsIgnoreCase("concat")) {
                return StringFunctions.concat(values, variables);
            } else if (values[2].equalsIgnoreCase("useridFromRange")) {
                return StringFunctions.userIdFromRange(values, false);
            } else if (values[2].equalsIgnoreCase("useridFromRangeInclude")) {
                return StringFunctions.userIdFromRange(values, true);
            } else if (values[2].equalsIgnoreCase("useridFromRangeExclude")) {
                return StringFunctions.userIdFromRange(values, false);
            } else if (values[2].equalsIgnoreCase("useridFromRangeWithMod")) {
                return StringFunctions.userIdFromRangeWithMod(values, true);
            } else if (values[2].equalsIgnoreCase("useridFromRangeWithModInclude")) {
                return StringFunctions.userIdFromRangeWithMod(values, true);
            } else if (values[2].equalsIgnoreCase("useridFromRangeWithModExclude")) {
                return StringFunctions.userIdFromRangeWithMod(values, false);
            } else if (values[2].equalsIgnoreCase("substring")) {
                if (values.length == 5) {
                    return StringFunctions.getSubstring(values[3], Integer.valueOf(values[4]), -1);
                } else if (values.length == 6)
                    try {
                        return StringFunctions.getSubstring(values[3], Integer.valueOf(values[4]),
                                Integer.valueOf(values[5]));
                    } catch (NumberFormatException nfe) {
                        return StringFunctions.getSubstring(addtlString, values[3], values[4]);
                    }
            }
            return "";
        } catch (Exception ex) {
            return "";
        }
    }

    private static String getSubstring(String string, String start, String end) {

        if (string == null)
            return "";

        int beginIndex = string.indexOf(start);
        if (beginIndex < 0)
            return "";

        String newString = string.substring(beginIndex + start.length());

        if (!end.equals("")) {
            int endIndex = newString.indexOf(end);
            if (endIndex > 0)
                newString = newString.substring(0, endIndex);
        }

        return newString;
    }

    /**
     * Combine the alpha lower and alpha upper collections into one
     * 
     * @return The combined collection
     */
    static private String[] alphaMixed() {
        return StringFunctions.combineStringArrays(StringFunctions.alphaLower, StringFunctions.alphaUpper);
    }

    /**
     * Combine the alpha mixed and numeric collections into one
     * 
     * @return The combined collection
     */
    static private String[] alphaMixedNumeric() {
        return StringFunctions.combineStringArrays(StringFunctions.alphaMixed(), StringFunctions.numeric);
    }

    /**
     * Combine the alpha mixed and special collections into one
     * 
     * @return The combined collection
     */
    static private String[] alphaMixedSpecial() {
        return StringFunctions.combineStringArrays(StringFunctions.alphaMixed(), StringFunctions.special);
    }

    // /**
    // * Combine the alpha mixed and unicode collections into one
    // *
    // * @return The combined collection
    // */
    // static private String[] alphaMixedUnicode() {
    // return StringFunctions.combineStringArrays(StringFunctions.alphaMixed(), StringFunctions.unicode);
    // }

    /**
     * Combine the alpha mixed, numeric and special collections into one
     * 
     * @return The combined collection
     */
    static private String[] alphaMixedNumericSpecial() {
        String[] step1 = StringFunctions.combineStringArrays(StringFunctions.alphaMixed(), StringFunctions.numeric);
        return StringFunctions.combineStringArrays(step1, StringFunctions.special);
    }

    //
    // /**
    // * Combine the alpha mixed, numeric, special and unicode collections into one
    // *
    // * @return The combined collection
    // */
    // static private String[] alphaMixedNumericSpecialUnicode() {
    // String[] step1 = StringFunctions.combineStringArrays(StringFunctions.alphaMixed(), StringFunctions.numeric);
    // String[] step2 = StringFunctions.combineStringArrays(step1, StringFunctions.special);
    // return StringFunctions.combineStringArrays(step2, StringFunctions.unicode);
    // }

    /**
     * Combine two String arrays into one
     * 
     * @param value1
     *            String[] One
     * @param value2
     *            String[] Two
     * @return One String array containing both sets of data
     */
    static private String[] combineStringArrays(String[] value1, String[] value2) {
        String[] output = new String[value1.length + value2.length];
        int counter = 0;
        for (int i = 0; i < value1.length; i++) {
            output[counter] = value1[i];
            ++counter;
        }
        for (int i = 0; i < value2.length; i++) {
            output[counter] = value2[i];
            ++counter;
        }
        return output;
    }

    /**
     * Get a random, positive whole number
     * 
     * 
     * 
     * @param length
     *            The length of the full numbers
     * @return A random whole number
     */
    static private String randomString(String[] values, int length) {
        StringBuilder output = new StringBuilder(length);
        for (int i = 0; i < length; i++)
            output.append(values[rnd.nextInt(values.length)]);
        return output.toString();
    }

    /**
     * Generate a random user date consisting of a prefix and a date
     * 
     * e.g. #function.string.userid.2.06-01-2011
     * 
     * @param prefixLength
     *            The length of the random prefix
     * @param dateFormat
     *            The format of the response (MM-dd-yyyy, MMddyyyy, etc)
     * @return The random user id
     */
    static private String userIdDate(int prefixLength, String dateFormat) {
        String[] dateRequest = { "#function", "date", "currentDate", dateFormat };
        String prefix = StringFunctions.randomString(StringFunctions.alphaMixedNumeric(), prefixLength);
        String date = DateFunctions.executeFunction(dateRequest);
        return prefix + date;
    }

    /**
     * Generate a random user id as an integer.
     * 
     * e.g. #function.string.useridFromRange.25.100
     * 
     * @param values
     *            Array values - [3] = minId, [4] = maxId, [5] = inclusions/inclusions list comma seperated regex to
     *            test the value
     * @param include
     *            The format for the date
     * @return The random user id
     */
    static private String userIdFromRange(String[] values, boolean include) {
        int minId = Integer.parseInt(values[3]);
        int maxId = Integer.parseInt(values[4]);
        String exclusions = values.length > 5 ? values[5] : null;
        Stack<Integer> stack = getStack(minId, maxId, exclusions, include);
        if (stack.size() > 0) {
            return Integer.toString(stack.pop());
        }
        throw new IllegalArgumentException(
                "Exhausted random User Ids. Range not large enough for the number of calls.");
    }

    /**
     * Generate a random user id in the range provided
     * 
     * e.g. #function.string.useridFromRange.25.100
     * 
     * @param prefixLength
     *            The length of the random prefix
     * @param dateFormat
     *            The format for the date
     * @return The random user id
     */
    static private String userIdFromRangeWithMod(String[] values, boolean include) {
        int minId = Integer.parseInt(values[3]);
        int maxId = Integer.parseInt(values[4]);
        int mod = Integer.parseInt(values[5]);
        Stack<Integer> stack = getStackWithMods(minId, maxId, mod, include);
        if (stack.size() > 0) {
            return Integer.toString(stack.pop());
        }
        throw new IllegalArgumentException(
                "Exhausted random User Ids. Range not large enough for the number of calls.");
    }

    /**
     * @param minId
     * @param maxId
     * @return
     */
    public synchronized static Stack<Integer> getStack(Integer minId, Integer maxId, String exclusions,
            boolean include) {
        String key = getStackKey(minId, maxId, exclusions, include);
        Stack<Integer> stack = stackMap.get(key);
        if (stack == null) {
            int blockSize = (maxId - minId) / APITestHarness.getInstance().getAgentRunData().getTotalAgents();
            int offset = APITestHarness.getInstance().getAgentRunData().getAgentInstanceNum() * blockSize;
            LOG.info(LogUtil.getLogMessage("Creating userId Block starting at " + (offset + minId)
                    + " and containing  " + blockSize + " entries with " + (include ? "inclusion" : "exclusion")
                    + " pattern(s) of " + exclusions, LogEventType.System));
            List<Integer> list = new ArrayList<Integer>();
            List<String> exclusionList = parseExclusions(exclusions);

            for (int i = 0; i < blockSize; i++) {
                int nextNum = i + minId + offset;
                if (nextNum < maxId) {
                    if (shouldInclude(Integer.toString(nextNum), exclusionList, include)) {
                        list.add(nextNum);
                    }
                }
            }
            Collections.shuffle(list);
            // Collections.reverse(list);
            stack = new Stack<Integer>();
            stack.addAll(list);
            stackMap.put(key, stack);
        }
        return stack;
    }

    /**
     * @param minId
     * @param maxId
     * @return
     */
    private synchronized static Stack<Integer> getStackWithMods(Integer minId, Integer maxId, Integer mod,
            boolean include) {
        String key = getStackKey(minId, maxId, mod, include);
        Stack<Integer> stack = stackMap.get(key);
        if (stack == null) {
            int blockSize = (maxId - minId) / APITestHarness.getInstance().getAgentRunData().getTotalAgents();
            int offset = APITestHarness.getInstance().getAgentRunData().getAgentInstanceNum() * blockSize;
            LOG.info(LogUtil.getLogMessage(
                    "Creating userId Block starting at " + offset + " and containing  " + blockSize + " entries.",
                    LogEventType.System));
            List<Integer> list = new ArrayList<Integer>();

            for (int i = 0; i < blockSize; i++) {
                int nextNum = i + minId + offset;
                if (include && nextNum < maxId && nextNum % mod == 0) {
                    list.add(nextNum);
                } else if (!include && nextNum < maxId && nextNum % mod != 0) {
                    list.add(nextNum);
                }
            }
            Collections.shuffle(list);
            // Collections.reverse(list);
            stack = new Stack<Integer>();
            stack.addAll(list);
            stackMap.put(key, stack);
        }
        return stack;
    }

    private static String getStackKey(Object minId, Object maxId, Object mod, boolean include) {
        return minId + "-" + maxId + "%" + mod + "-" + (include ? "include" : "exclude");
    }

    private static List<String> parseExclusions(String exclusions) {
        List<String> ret = new ArrayList<String>();
        if (!StringUtils.isBlank(exclusions)) {
            String[] terms = exclusions.split(",");
            for (String term : terms) {
                ret.add(term.trim());
            }
        }
        return ret;
    }

    public static boolean shouldInclude(String value, List<String> expressions, boolean include) {
        boolean isMatch = false;
        for (String exp : expressions) {
            isMatch = isMatch | value.matches(exp);
        }
        return include ? isMatch : !isMatch;
    }

    /**
     * Generates a string that is a concatenation of the strings, 0-n, passed in. Evaluates strings for variables and
     * will concat the variable value, not name, to string.
     * 
     * @param values
     *            List of Strings to concat starting at index 3 in array
     * @return Concatenation of strings
     */
    static private String concat(String[] values, Variables variables) {

        String generatedStr = "";

        for (int str = 3; str < values.length; str++) {
            String strToAdd = values[str];
            if (strToAdd != null) {
                // check if string is variable
                if (ValidationUtil.isVariable(strToAdd)) {
                    strToAdd = variables.getVariable(strToAdd);
                }
                generatedStr = generatedStr.concat(strToAdd);
            }
        }

        return generatedStr;
    }

    /**
     * Get a substring from a string
     * 
     * @param subject
     *            The original string
     * @param start
     *            The location to start at
     * @param stop
     *            The location to end at; -1 if end of string
     * @return
     */
    static private String getSubstring(String subject, int start, int stop) {
        if (stop == -1 || stop >= subject.length()) {
            return subject.substring(start);
        }
        return subject.substring(start, stop);
    }

}