/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.scripting.general;
import java.util.ArrayList;
import java.util.Random;
import com.slamd.scripting.engine.Argument;
import com.slamd.scripting.engine.Method;
import com.slamd.scripting.engine.ScriptException;
import com.slamd.scripting.engine.Variable;
/**
* This class defines a string array variable that holds zero or more string
* values. It also defines a set of methods for dealing with string array
* variables:
*
* <UL>
* <LI>addValue(string value) -- Adds the specified string value to this
* string array. This method does not return a value.</LI>
* <LI>assign(stringarray values) -- Initializes this string array variable
* with the information in the provided string array. This method does
* not return a value.</LI>
* <LI>contains(string value, boolean ignoreCase) -- Determines whether this
* array contains the specified string value and returns the result as a
* Boolean value.</LI>
* <LI>firstValue() -- Retrieves the first value in this string array as a
* string value. If there are no values, then a null string will be
* returned.</LI>
* <LI>indexOf(string value, boolean ignoreCase) -- Determines the location of
* the specified string value in this array and returns the result as an
* integer value.</LI>
* <LI>indexOf(string value, int startPos, boolean ignoreCase) -- Determines
* the location of the specified string value in this array starting at
* the specified position and returns the result as an integer value.</LI>
* <LI>insert(string value, int position) -- Inserts the specified string
* value at the indicated position in this string array. This method does
* not return a value.</LI>
* <LI>isEmpty() -- Returns a Boolean value that indicates whether this string
* array is empty (i.e., has no values).</LI>
* <LI>isNotEmpty() -- Returns a Boolean value that indicates whether this
* string array is empty (i.e., has no values).</LI>
* <LI>length() -- Returns the number of elements in this string array as an
* integer value.</LI>
* <LI>nextValue() -- Returns the next value from this string array as a
* string value. If there are no more values, then a null string will be
* returned.</LI>
* <LI>randomValue() -- Returns a value from a random position in this string
* array as a string value. If there are no values, then a null string
* will be returned.</LI>
* <LI>remove(string value, boolean ignoreCase) -- Removes the first
* occurrence of the specified value from this string array. This method
* returns a Boolean value that indicates whether a value was actually
* removed.</LI>
* <LI>removeAll() -- Removes all values in this string array. This method
* does not return a value.</LI>
* <LI>removeValueAt(int position) -- Removes the value at the specified
* position from this array. This method returns the string value that
* was removed.</LI>
* <LI>setValueAt(string value, int position) -- Replaces the current value at
* the specified position with the provided value. This method does not
* return a value.</LI>
* <LI>valueAt(int position) -- Retrieves the string value at the specified
* position in this array.</LI>
* </UL>
*
*
* @author Neil A. Wilson
*/
public class StringArrayVariable
extends Variable
{
/**
* The name that will be used for the data type of string array variables.
*/
public static final String STRING_ARRAY_VARIABLE_TYPE = "stringarray";
/**
* The name of the method that will be used to add a new value to this array.
*/
public static final String ADD_VALUE_METHOD_NAME = "addvalue";
/**
* The method number for the "addValue" method.
*/
public static final int ADD_VALUE_METHOD_NUMBER = 0;
/**
* The name of the method that will be used to initialize this array.
*/
public static final String ASSIGN_METHOD_NAME = "assign";
/**
* The method number for the "assign" method.
*/
public static final int ASSIGN_METHOD_NUMBER = 1;
/**
* The name of the method that will be used to determine if this method
* contains the specified value.
*/
public static final String CONTAINS_METHOD_NAME = "contains";
/**
* The method number for the "contains" method.
*/
public static final int CONTAINS_METHOD_NUMBER = 2;
/**
* The name of the method that will be used to retrieve the first value from
* this array.
*/
public static final String FIRST_VALUE_METHOD_NAME = "firstvalue";
/**
* The method number for the "firstValue" method.
*/
public static final int FIRST_VALUE_METHOD_NUMBER = 3;
/**
* The name of the method that will be used to determine the position of the
* specified value.
*/
public static final String INDEX_OF_METHOD_NAME = "indexof";
/**
* The method number for the first "indexOf" method.
*/
public static final int INDEX_OF_1_METHOD_NUMBER = 4;
/**
* The method number for the second "indexOf" method.
*/
public static final int INDEX_OF_2_METHOD_NUMBER = 5;
/**
* The name of the method that will be used to insert a value into this array.
*/
public static final String INSERT_METHOD_NAME = "insert";
/**
* The method number for the "insert" method.
*/
public static final int INSERT_METHOD_NUMBER = 6;
/**
* The name of the method that will determine if this array is empty.
*/
public static final String IS_EMPTY_METHOD_NAME = "isempty";
/**
* The method number for the "isEmpty" method.
*/
public static final int IS_EMPTY_METHOD_NUMBER = 7;
/**
* The name of the method that will determine if this array is not empty.
*/
public static final String IS_NOT_EMPTY_METHOD_NAME = "isnotempty";
/**
* The method number for the "isNotEmpty" method.
*/
public static final int IS_NOT_EMPTY_METHOD_NUMBER = 8;
/**
* The name of the method that will be used to determine the number of
* elements in this array.
*/
public static final String LENGTH_METHOD_NAME = "length";
/**
* The method number for the "length" method.
*/
public static final int LENGTH_METHOD_NUMBER = 9;
/**
* The name of the method that will be used to retrieve the next value from
* the array.
*/
public static final String NEXT_VALUE_METHOD_NAME = "nextvalue";
/**
* The method number for the "nextValue" method.
*/
public static final int NEXT_VALUE_METHOD_NUMBER = 10;
/**
* The name of the method that will be used to retrieve a random value from
* the array.
*/
public static final String RANDOM_VALUE_METHOD_NAME = "randomvalue";
/**
* the method number for the "randomValue" method.
*/
public static final int RANDOM_VALUE_METHOD_NUMBER = 11;
/**
* The name of the method that will be used to remove a value from this array.
*/
public static final String REMOVE_METHOD_NAME = "remove";
/**
* The method number for the "remove" method.
*/
public static final int REMOVE_METHOD_NUMBER = 12;
/**
* The name of the method that will be used to remove all values from this
* array.
*/
public static final String REMOVE_ALL_METHOD_NAME = "removeall";
/**
* The method number for the "removeAll" method.
*/
public static final int REMOVE_ALL_METHOD_NUMBER = 13;
/**
* The name of the method that will be used to remove the value at the
* specified position from the array.
*/
public static final String REMOVE_VALUE_AT_METHOD_NAME = "removevalueat";
/**
* The method number for the "removeValueAt" method.
*/
public static final int REMOVE_VALUE_AT_METHOD_NUMBER = 14;
/**
* The name of the method that will be used to set the value at the specified
* position in the array.
*/
public static final String SET_VALUE_AT_METHOD_NAME = "setvalueat";
/**
* The method number for the "setValueAt" method.
*/
public static final int SET_VALUE_AT_METHOD_NUMBER = 15;
/**
* The name of the method that will be used to retrieve the value at the
* specified position in the array.
*/
public static final String VALUE_AT_METHOD_NAME = "valueat";
/**
* The method number for the "valueAt" method.
*/
public static final int VALUE_AT_METHOD_NUMBER = 16;
/**
* The set of methods associated with string array variables.
*/
public static final Method[] STRING_ARRAY_VARIABLE_METHODS = new Method[]
{
new Method(ADD_VALUE_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE }, null),
new Method(ASSIGN_METHOD_NAME, new String[] { STRING_ARRAY_VARIABLE_TYPE },
null),
new Method(CONTAINS_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
BooleanVariable.BOOLEAN_VARIABLE_TYPE },
BooleanVariable.BOOLEAN_VARIABLE_TYPE),
new Method(FIRST_VALUE_METHOD_NAME, new String[0],
StringVariable.STRING_VARIABLE_TYPE),
new Method(INDEX_OF_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
BooleanVariable.BOOLEAN_VARIABLE_TYPE },
IntegerVariable.INTEGER_VARIABLE_TYPE),
new Method(INDEX_OF_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
IntegerVariable.INTEGER_VARIABLE_TYPE,
BooleanVariable.BOOLEAN_VARIABLE_TYPE },
IntegerVariable.INTEGER_VARIABLE_TYPE),
new Method(INSERT_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
IntegerVariable.INTEGER_VARIABLE_TYPE }, null),
new Method(IS_EMPTY_METHOD_NAME, new String[0],
BooleanVariable.BOOLEAN_VARIABLE_TYPE),
new Method(IS_NOT_EMPTY_METHOD_NAME, new String[0],
BooleanVariable.BOOLEAN_VARIABLE_TYPE),
new Method(LENGTH_METHOD_NAME, new String[0],
IntegerVariable.INTEGER_VARIABLE_TYPE),
new Method(NEXT_VALUE_METHOD_NAME, new String[0],
StringVariable.STRING_VARIABLE_TYPE),
new Method(RANDOM_VALUE_METHOD_NAME, new String[0],
StringVariable.STRING_VARIABLE_TYPE),
new Method(REMOVE_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
BooleanVariable.BOOLEAN_VARIABLE_TYPE },
BooleanVariable.BOOLEAN_VARIABLE_TYPE),
new Method(REMOVE_ALL_METHOD_NAME, new String[0], null),
new Method(REMOVE_VALUE_AT_METHOD_NAME,
new String[] { IntegerVariable.INTEGER_VARIABLE_TYPE },
StringVariable.STRING_VARIABLE_TYPE),
new Method(SET_VALUE_AT_METHOD_NAME,
new String[] { StringVariable.STRING_VARIABLE_TYPE,
IntegerVariable.INTEGER_VARIABLE_TYPE }, null),
new Method(VALUE_AT_METHOD_NAME,
new String[] { IntegerVariable.INTEGER_VARIABLE_TYPE },
StringVariable.STRING_VARIABLE_TYPE)
};
// The position of the value that will be retrieved with the next call to
// "nextValue".
private int valuePosition;
// The random number generator.
private Random random;
// The set of values associated with this array.
private ArrayList<String> stringValues;
/**
* Creates a new variable with no name, to be used only when creating a
* variable with <CODE>Class.newInstance()</CODE>, and only when
* <CODE>setName()</CODE> is called after that to set the name.
*
* @throws ScriptException If a problem occurs while initializing the new
* variable.
*/
public StringArrayVariable()
throws ScriptException
{
stringValues = new ArrayList<String>();
random = new Random();
valuePosition = 0;
}
/**
* Creates a new string array variable with the specified set of values.
*
* @param values The set of values to use for this string array variable.
*/
public StringArrayVariable(String[] values)
{
stringValues = new ArrayList<String>();
random = new Random();
valuePosition = 0;
for (int i=0; i < values.length; i++)
{
stringValues.add(values[i]);
}
}
/**
* Retrieves the set of string values associated with this variable.
*
* @return The set of string values associated with this variable.
*/
public String[] getStringValues()
{
String[] returnValues = new String[stringValues.size()];
stringValues.toArray(returnValues);
return returnValues;
}
/**
* Specifies the set of string values for this variable.
*
* @param stringValues The set of string values for this variable.
*/
public void setStringValues(String[] stringValues)
{
this.stringValues.clear();
for (int i=0; i < stringValues.length; i++)
{
this.stringValues.add(stringValues[i]);
}
}
/**
* Adds the specified value to this string array.
*
* @param stringValue The value to add to this string array.
*/
public void addStringValue(String stringValue)
{
stringValues.add(stringValue);
}
/**
* Retrieves the name of the variable type for this variable.
*
* @return The name of the variable type for this variable.
*/
@Override()
public String getVariableTypeName()
{
return STRING_ARRAY_VARIABLE_TYPE;
}
/**
* Retrieves a list of all methods defined for this variable.
*
* @return A list of all methods defined for this variable.
*/
@Override()
public Method[] getMethods()
{
return STRING_ARRAY_VARIABLE_METHODS;
}
/**
* Indicates whether this variable type has a method with the specified name.
*
* @param methodName The name of the method.
*
* @return <CODE>true</CODE> if this variable has a method with the specified
* name, or <CODE>false</CODE> if it does not.
*/
@Override()
public boolean hasMethod(String methodName)
{
for (int i=0; i < STRING_ARRAY_VARIABLE_METHODS.length; i++)
{
if (STRING_ARRAY_VARIABLE_METHODS[i].getName().equals(methodName))
{
return true;
}
}
return false;
}
/**
* Retrieves the method number for the method that has the specified name and
* argument types, or -1 if there is no such method.
*
* @param methodName The name of the method.
* @param argumentTypes The list of argument types for the method.
*
* @return The method number for the method that has the specified name and
* argument types.
*/
@Override()
public int getMethodNumber(String methodName, String[] argumentTypes)
{
for (int i=0; i < STRING_ARRAY_VARIABLE_METHODS.length; i++)
{
if (STRING_ARRAY_VARIABLE_METHODS[i].hasSignature(methodName,
argumentTypes))
{
return i;
}
}
return -1;
}
/**
* Retrieves the return type for the method with the specified name and
* argument types.
*
* @param methodName The name of the method.
* @param argumentTypes The set of argument types for the method.
*
* @return The return type for the method, or <CODE>null</CODE> if there is
* no such method defined.
*/
@Override()
public String getReturnTypeForMethod(String methodName,
String[] argumentTypes)
{
for (int i=0; i < STRING_ARRAY_VARIABLE_METHODS.length; i++)
{
if (STRING_ARRAY_VARIABLE_METHODS[i].hasSignature(methodName,
argumentTypes))
{
return STRING_ARRAY_VARIABLE_METHODS[i].getReturnType();
}
}
return null;
}
/**
* Executes the specified method, using the provided variables as arguments
* to the method, and makes the return value available to the caller.
*
* @param lineNumber The line number of the script in which the method
* call occurs.
* @param methodNumber The method number of the method to execute.
* @param arguments The set of arguments to use for the method.
*
* @return The value returned from the method, or <CODE>null</CODE> if it
* does not return a value.
*
* @throws ScriptException If the specified method does not exist, or if a
* problem occurs while attempting to execute it.
*/
@Override()
public Variable executeMethod(int lineNumber, int methodNumber,
Argument[] arguments)
throws ScriptException
{
switch (methodNumber)
{
case ADD_VALUE_METHOD_NUMBER:
// Get the value of the new string to add and add it to the value set.
StringVariable sv = (StringVariable) arguments[0].getArgumentValue();
stringValues.add(sv.getStringValue());
// This method does not return a value.
return null;
case ASSIGN_METHOD_NUMBER:
// Get the string array and use its values.
StringArrayVariable sav = (StringArrayVariable)
arguments[0].getArgumentValue();
setStringValues(sav.getStringValues());
// This method does not return a value.
return null;
case CONTAINS_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
String value = sv.getStringValue();
// Get the value of the Boolean argument.
BooleanVariable bv = (BooleanVariable) arguments[1].getArgumentValue();
boolean ignoreCase = bv.getBooleanValue();
// Iterate through all the values until we find a match or reach the end
// of the list.
boolean matchFound = false;
int size = stringValues.size();
for (int i=0; i < size; i++)
{
if (ignoreCase)
{
if (value.equalsIgnoreCase(stringValues.get(i)))
{
matchFound = true;
break;
}
}
else
{
if (value.equals(stringValues.get(i)))
{
matchFound = true;
break;
}
}
}
// Return the result as a Boolean variable.
return new BooleanVariable(matchFound);
case FIRST_VALUE_METHOD_NUMBER:
// Return the first value as a string and reset the value position
// indicator.
if (! stringValues.isEmpty())
{
valuePosition = 1;
return new StringVariable(stringValues.get(0));
}
else
{
valuePosition = 0;
return new StringVariable();
}
case INDEX_OF_1_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
value = sv.getStringValue();
// Get the value of the Boolean argument.
bv = (BooleanVariable) arguments[1].getArgumentValue();
ignoreCase = bv.getBooleanValue();
// Iterate through all the values until we find a match or reach the end
// of the list.
int position = -1;
size = stringValues.size();
for (int i=0; i < size; i++)
{
if (ignoreCase)
{
if (value.equalsIgnoreCase(stringValues.get(i)))
{
position = i;
break;
}
}
else
{
if (value.equals(stringValues.get(i)))
{
position = i;
break;
}
}
}
// Return the result as an integer variable.
return new IntegerVariable(position);
case INDEX_OF_2_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
value = sv.getStringValue();
// Get the value of the integer argument.
IntegerVariable iv = (IntegerVariable) arguments[1].getArgumentValue();
int startPos = iv.getIntValue();
// Get the value of the Boolean argument.
bv = (BooleanVariable) arguments[2].getArgumentValue();
ignoreCase = bv.getBooleanValue();
// Iterate through all the values until we find a match or reach the end
// of the list.
position = -1;
size = stringValues.size();
for (int i=startPos; i < size; i++)
{
if (ignoreCase)
{
if (value.equalsIgnoreCase(stringValues.get(i)))
{
position = i;
break;
}
}
else
{
if (value.equals(stringValues.get(i)))
{
position = i;
break;
}
}
}
// Return the result as an integer variable.
return new IntegerVariable(position);
case INSERT_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
value = sv.getStringValue();
// Get the value of the integer argument.
iv = (IntegerVariable) arguments[1].getArgumentValue();
position = iv.getIntValue();
// Insert the value in the specified position and don't return a value.
stringValues.add(position, value);
return null;
case IS_EMPTY_METHOD_NUMBER:
// Return a Boolean value that indicates whether this array is empty.
return new BooleanVariable(stringValues.isEmpty());
case IS_NOT_EMPTY_METHOD_NUMBER:
// Return a Boolean value that indicates whether this array is not
// empty.
return new BooleanVariable(! stringValues.isEmpty());
case LENGTH_METHOD_NUMBER:
// Return the number of elements as an integer value.
return new IntegerVariable(stringValues.size());
case NEXT_VALUE_METHOD_NUMBER:
// Return the next value as a string and update the value position
// indicator.
if (stringValues.size() > valuePosition)
{
return new StringVariable(stringValues.get(valuePosition++));
}
else
{
return new StringVariable();
}
case RANDOM_VALUE_METHOD_NUMBER:
// Return the next value as a string and update the value position
// indicator.
if (! stringValues.isEmpty())
{
position = Math.abs(random.nextInt()) % stringValues.size();
return new StringVariable(stringValues.get(position));
}
else
{
return new StringVariable();
}
case REMOVE_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
value = sv.getStringValue();
// Get the value of the Boolean argument.
bv = (BooleanVariable) arguments[1].getArgumentValue();
ignoreCase = bv.getBooleanValue();
// Iterate through all the values until we find a match or reach the end
// of the list.
matchFound = false;
size = stringValues.size();
for (int i=0; i < size; i++)
{
if (ignoreCase)
{
if (value.equalsIgnoreCase(stringValues.get(i)))
{
matchFound = true;
stringValues.remove(i);
break;
}
}
else
{
if (value.equals(stringValues.get(i)))
{
matchFound = true;
stringValues.remove(i);
break;
}
}
}
// Return the result as a Boolean variable.
return new BooleanVariable(matchFound);
case REMOVE_ALL_METHOD_NUMBER:
// Remove all elements and don't return a value.
stringValues.clear();
return null;
case REMOVE_VALUE_AT_METHOD_NUMBER:
// Get the value of the integer argument.
iv = (IntegerVariable) arguments[0].getArgumentValue();
position = iv.getIntValue();
// Remove the value and return the value removed as a string.
return new StringVariable(stringValues.remove(position));
case SET_VALUE_AT_METHOD_NUMBER:
// Get the value of the string argument.
sv = (StringVariable) arguments[0].getArgumentValue();
value = sv.getStringValue();
// Get the value of the integer argument.
iv = (IntegerVariable) arguments[1].getArgumentValue();
position = iv.getIntValue();
// Replace the value in the specified position and don't return a value.
stringValues.set(position, value);
return null;
case VALUE_AT_METHOD_NUMBER:
// Get the value of the integer argument.
iv = (IntegerVariable) arguments[0].getArgumentValue();
position = iv.getIntValue();
// Return the value as a string.
return new StringVariable(stringValues.get(position));
default:
throw new ScriptException(lineNumber,
"There is no method " + methodNumber +
" defined for " + getArgumentType() +
" variables.");
}
}
/**
* Assigns the value of the provided argument to this variable. The value of
* the provided argument must be of the same type as this variable.
*
* @param argument The argument whose value should be assigned to this
* variable.
*
* @throws ScriptException If a problem occurs while performing the
* assignment.
*/
@Override()
public void assign(Argument argument)
throws ScriptException
{
if (! argument.getArgumentType().equals(STRING_ARRAY_VARIABLE_TYPE))
{
throw new ScriptException("Attempt to assign an argument of type " +
argument.getArgumentType() +
" to a variable of type " +
STRING_ARRAY_VARIABLE_TYPE + " rejected.");
}
StringArrayVariable sav = (StringArrayVariable) argument.getArgumentValue();
stringValues = sav.stringValues;
valuePosition = sav.valuePosition;
}
/**
* Retrieves a string representation of the value of this argument.
*
* @return A string representation of the value of this argument.
*/
public String getValueAsString()
{
int numValues = stringValues.size();
switch (numValues)
{
case 0:
return "{ no values }";
case 1:
case 2:
case 3:
case 4:
case 5:
StringBuilder buffer = new StringBuilder();
buffer.append("{ ");
buffer.append('"');
buffer.append(stringValues.get(0));
buffer.append('"');
for (int i=1; i < numValues; i++)
{
buffer.append(", ");
buffer.append('"');
buffer.append(stringValues.get(i));
buffer.append('"');
}
buffer.append(" }");
return buffer.toString();
default:
return "{ " + stringValues.size() + " values }";
}
}
}