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

Java tutorial

Introduction

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

Source

/*
 * Copyright 2012 Intuit Inc. All Rights Reserved
 */

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.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
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.codec.binary.Base64;
import org.apache.commons.jexl2.JexlContext;
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.logging.LogEventType;
import com.intuit.tank.vm.common.util.ExpressionContextVisitor;

/**
 * 
 * JexlStringFunctions functions useful for String info. Functions start with #stringFunctions.functionName(parameters).
 * 
 * @author dangleton
 * @author rchalmela
 * 
 */

public class JexlStringFunctions implements ExpressionContextVisitor {

    private static final Logger LOG = Logger.getLogger(JexlStringFunctions.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>>();

    /**
     * @{inheritDoc
     */
    @Override
    public void visit(JexlContext context) {
        context.set("stringFunctions", this);
    }

    public static void resetStatics() {
        stackMap.clear();
    }

    /**
     * Get a random, positive whole number
     * 
     * @param length
     *            The length of the full numbers
     * @return A random whole number
     */
    private String randomString(String[] values, Object olength) {
        int length = FunctionHandler.getInt(olength);
        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
     * 
     * @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
     */
    public String userIdFromDate(Object prefixLength, String dateFormat) {
        return userIdDate(prefixLength, dateFormat);
    }

    /**
     * Generate a random user date consisting of a prefix and a date
     * 
     * @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
     */
    public String userIdDate(Object oprefixLength, String dateFormat) {
        int prefixLength = FunctionHandler.getInt(oprefixLength);
        String prefix = randomString(alphaMixedNumeric(), prefixLength);
        String date = new SimpleDateFormat(dateFormat).format(new java.util.Date());
        return prefix + date;
    }

    /**
     * Generate a random user id in the range provided
     * 
     * @param prefixLength
     *            The length of the random prefix
     * @param dateFormat
     *            The format for the date
     * @return The random user id
     */
    public String userIdFromRange(Object ominId, Object omaxId) {
        int minId = FunctionHandler.getInt(ominId);
        int maxId = FunctionHandler.getInt(omaxId);
        Stack<Integer> stack = getStack(minId, maxId);
        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
     */
    private synchronized Stack<Integer> getStack(Integer minId, Integer maxId) {
        String key = getStackKey(minId, maxId);
        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;
                list.add(nextNum);
            }
            Collections.shuffle(list);
            // Collections.reverse(list);
            stack = new Stack<Integer>();
            stack.addAll(list);
            stackMap.put(key, stack);
        }
        return stack;
    }

    private String getStackKey(Object minId, Object maxId) {
        return minId + "-" + maxId;
    }

    /**
     * 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
     */
    public String concat(String... values) {
        return StringUtils.join(values);
    }

    /**
     * Get a substring from a string
     * 
     * @param subject
     *            The original string
     * @param start
     *            The location to start at
     * @return
     */
    public String substring(String subject, int start) {
        return substring(subject, start, -1);
    }

    /**
     * <p>
     * Gets the String that is nested in between two Strings.
     * 
     * Only the first match is returned.
     * </p>
     * 
     * <p>
     * A <code>null</code> input String returns <code>null</code>. A <code>null</code> open/close returns
     * <code>null</code> (no match). An empty ("") open and close returns an empty string.
     * </p>
     * 
     * <pre>
     * StringUtils.substringBetween("wx[b]yz", "[", "]") = "b"
     * StringUtils.substringBetween(null, *, *)          = null
     * StringUtils.substringBetween(*, null, *)          = null
     * StringUtils.substringBetween(*, *, null)          = null
     * StringUtils.substringBetween("", "", "")          = ""
     * StringUtils.substringBetween("", "", "]")         = null
     * StringUtils.substringBetween("", "[", "]")        = null
     * StringUtils.substringBetween("yabcz", "", "")     = ""
     * StringUtils.substringBetween("yabcz", "y", "z")   = "abc"
     * StringUtils.substringBetween("yabczyabcz", "y", "z")   = "abc"
     * </pre>
     * 
     * @param subject
     *            the String containing the substring, may be null
     * @param open
     *            the String before the substring, may be null
     * @param close
     *            the String after the substring, may be null
     * @return the substring, <code>null</code> if no match
     */
    public String substringBetween(String subject, String open, String close) {
        return substringBetween(subject, open, close, 0);
    }

    /**
     * <p>
     * Gets the nth String that is nested in between two Strings.
     * 
     * </p>
     * 
     * <p>
     * A <code>null</code> input String returns <code>null</code>. A <code>null</code> open/close returns
     * <code>null</code> (no match). An empty ("") open and close returns an empty string.
     * </p>
     * 
     * @param subject
     *            the String containing the substring, may be null
     * @param open
     *            the String before the substring, may be null
     * @param close
     *            the String after the substring, may be null
     * @param index
     *            the zero based index of the string to return.
     * @return the substring, <code>null</code> if no match
     */
    public String substringBetween(String subject, String open, String close, int index) {
        String[] strings = internalSubstringsBetween(subject, open, close);
        if (index >= 0 && index < strings.length) {
            return strings[index];
        }
        return null;
    }

    private String[] internalSubstringsBetween(String subject, String open, String close) {
        String[] ret = null;
        if (subject != null && open == null && close != null) {
            ret = new String[] { StringUtils.substringBefore(subject, close) };
        } else if (subject != null && open != null && close == null) {
            ret = new String[] { StringUtils.substringAfterLast(subject, open) };
        } else {
            ret = StringUtils.substringsBetween(subject, open, close);
        }
        return ret != null ? ret : new String[0];
    }

    public String replaceBetween(String subject, String open, String close, String replace, boolean encodeData) {
        if (subject == null) {
            return subject;
        }
        if (encodeData) {
            // decode the string
            subject = fromBase64(subject);
        }
        int indexStart = 0;
        int indexEnd = subject.length();
        if (open != null) {
            indexStart = subject.indexOf(open);
        }
        if (close != null) {
            indexEnd = subject.indexOf(close, indexStart + open.length());
        }

        if (indexStart == -1 || indexEnd == -1) {
            // do nothing
        } else {
            String s1 = open != null ? subject.substring(0, (indexStart + open.length())) : "";
            String s2 = close != null ? subject.substring(indexEnd) : "";
            subject = s1 + replace + s2;
        }
        if (encodeData) {// encode it again
            subject = toBase64(subject);
        }
        return subject;
    }

    public static void main(String[] args) {
        String test = "Test";
        int indexOf = test.indexOf("s", -1);
        System.out.println(indexOf);
    }

    /**
     * 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
     */
    public String substring(String subject, int start, int stop) {
        if (stop == -1 || stop >= subject.length()) {
            return subject.substring(start);
        }
        return subject.substring(start, stop);
    }

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

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

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

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

    /**
     * Combine two String arrays into one
     * 
     * @param value1
     *            String[] One
     * @param value2
     *            String[] Two
     * @return One String array containing both sets of data
     */
    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 string of lower case letters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaLower(int length) {
        return randomString(JexlStringFunctions.alphaLower, length);
    }

    /**
     * Get a random string of upper case letters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaUpper(int length) {
        return randomString(JexlStringFunctions.alphaUpper, length);
    }

    /**
     * Get a random string of lower and upper case letters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaMixed(int length) {
        return randomString(alphaMixed(), length);
    }

    /**
     * Get a random string of numerals
     * 
     * @param length
     * @return random string
     */
    public String randomNumeric(int length) {
        return randomString(JexlStringFunctions.numeric, length);
    }

    /**
     * Get a random string of special characters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomSpecial(int length) {
        return randomString(JexlStringFunctions.special, length);
    }

    /**
     * Get a random string of lower and upper case letters and numerals of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaMixedNumeric(int length) {
        return randomString(alphaMixedNumeric(), length);
    }

    /**
     * Get a random string of lower and upper case letters and special characters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaMixedSpecial(int length) {
        return randomString(alphaMixedSpecial(), length);
    }

    /**
     * Get a random string of lower and upper case letters, numerals and special characters of given length
     * 
     * @param length
     * @return random string
     */
    public String randomAlphaMixedNumericSpecial(int length) {
        return randomString(alphaMixedNumericSpecial(), length);
    }

    /**
     * Returns a string's base64 encoding
     * 
     * @param toEncode
     * @return base64 string
     */
    public String toBase64(String toEncode) {
        try {
            byte[] bytes = toEncode.getBytes();
            return new String(Base64.encodeBase64(bytes), Charset.forName("utf-8")).trim();
        } catch (Exception e) {
            LOG.error("Error base64 encoding " + toEncode + ": " + e);
        }
        return toEncode;
    }

    /**
     * Returns a string's decoded from base 64
     * 
     * @param toDecode
     *            the string to decode
     * @return base64 string
     */
    public String fromBase64(String toDecode) {
        try {
            byte[] bytes = Base64.decodeBase64(toDecode.trim());
            return new String(bytes, Charset.forName("utf-8"));
        } catch (Exception e) {
            LOG.error("Error base64 decoding " + toDecode + ": " + e);
        }
        return toDecode;
    }

    /**
     * Get a byte array's base64 endcoding
     * 
     * @param bytes
     * @return a base64 string
     */
    public String byteArrayToBase64(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    /**
     * Encodes a String using a URL encoder
     * 
     * @param toEncode
     *            the String to encode
     * @return the encoded String
     */
    public String urlEncode(String toEncode) {
        try {
            return URLEncoder.encode(toEncode, "utf-8");
        } catch (Exception e) {
            LOG.error("Error url encoding " + toEncode + ": " + e);
        }
        return toEncode;
    }

    /**
     * URL Decodes the given string
     * 
     * @param toDecode
     *            the String to decode
     * @return the decoded string
     */
    public String urlDecode(String toDecode) {
        try {
            return URLDecoder.decode(toDecode, "utf-8");
        } catch (Exception e) {
            LOG.error("Error url decoding " + toDecode + ": " + e);
        }
        return toDecode;
    }
}