package com.intuit.tank.harness.test.data;
/*
* #%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.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.intuit.tank.harness.APITestHarness;
import com.intuit.tank.harness.functions.FunctionHandler;
import com.intuit.tank.harness.functions.JexlDateFunctions;
import com.intuit.tank.harness.functions.JexlIOFunctions;
import com.intuit.tank.harness.functions.JexlMonetaryFunctions;
import com.intuit.tank.harness.functions.JexlNumericFunctions;
import com.intuit.tank.harness.functions.JexlStringFunctions;
import com.intuit.tank.harness.functions.JexlTaxFunctions;
import com.intuit.tank.harness.logging.LogUtil;
import com.intuit.tank.harness.test.KillScriptException;
import com.intuit.tank.logging.LogEventType;
import com.intuit.tank.logging.LoggingProfile;
import com.intuit.tank.vm.common.TankConstants;
import com.intuit.tank.vm.common.util.ValidationUtil;
import com.intuit.tank.vm.settings.TankConfig;
public class Variables {
public static final String RETRY_KEY = "_retry_enabled_";
static Logger LOG = LogManager.getLogger(Variables.class);
private HashMap<String, VariableValue> variables = null;
private boolean doLog = false;
private static JexlEngine jexl = new JexlEngine();
private static final Pattern p = Pattern.compile(TankConstants.EXPRESSION_REGEX);
static {
jexl.setCache(1024);
jexl.setLenient(true);
jexl.setSilent(true);
}
private JexlContext context;
/**
* Get the single instance of the variables class
*
* @return The variable class instance
*
* static public Variables getInstance(){ if (Variables.instance == null) Variables.instance = new
* Variables(); return Variables.instance; }
*
* /** Constructor
*/
public Variables() {
this.variables = new HashMap<String, VariableValue>();
try {
doLog = new TankConfig().getAgentConfig().getLogVariables();
} catch (Exception e) {
// eat this one
}
context = new MapContext();
new JexlStringFunctions().visit(context);
new JexlIOFunctions().visit(context);
new JexlDateFunctions().visit(context);
new JexlMonetaryFunctions().visit(context);
new JexlNumericFunctions().visit(context);
new JexlTaxFunctions().visit(context);
// get from config??
}
/**
* @return the context
*/
public JexlContext getContext() {
return context;
}
public String evaluate(String s) {
if (StringUtils.isNotEmpty(s)) {
if (s.contains("#")) { // Performance Shortcut
Matcher m = p.matcher(s);
while (m.find()) { // find next match, very costly
String match = m.group();
String group = m.group(1);
Expression expression = jexl.createExpression(group);
String result = (String) expression.evaluate(context);
if (result == null && (group.contains("getCSVData") || group.contains("getFile"))) {
APITestHarness.getInstance().addKill();
LOG.error(LogUtil.getLogMessage("CSV file (" + group + ") has no more data.",
LogEventType.Validation, LoggingProfile.USER_VARIABLE));
throw new KillScriptException("CSV file (" + group + ") has no more data.");
}
s = StringUtils.replace(s, match, result != null ? result : "");
}
}
}
return s;
}
public Map<String, String> getVaribleValues() {
Map<String, String> ret = new HashMap<String, String>();
for (Entry<String, VariableValue> entry : variables.entrySet()) {
ret.put(entry.getKey(), entry.getValue().getValue());
}
return ret;
}
/**
* Does the variable exist in the list
*
* @param key
* The variable name
* @return TRUE if the variable is in the list; FALSE otherwise
*/
public boolean variableExists(String key) {
if (StringUtils.isEmpty(key)) {
return false;
}
key = ValidationUtil.removeVariableIdentifier(key);
return this.variables.containsKey(key);
}
/**
* Add a variable to the map
*
* @param key
* The key name
* @param value
* The key value
*/
public void addVariable(String key, String value) {
addVariable(key, value, true);
}
/**
* Add a variable to the map
*
* @param key
* The key name
* @param value
* The key value
* @param allowOverride
* true to allow override of variable
*/
public void addVariable(String key, String value, boolean allowOverride) {
String result = null;
if (value.length() < 1) {
result = this.processString(key, value);
} else if (ValidationUtil.isFunction(value)) {
result = this.processFunction(key, value);
} else {
result = this.processString(key, value);
}
VariableValue variableValue = this.variables.get(key);
if (variableValue == null || variableValue.allowOverride) {
this.variables.put(key, new VariableValue(result, allowOverride));
context.set(key, result);
}
}
/**
* Get the value for a variable
*
* @param key
* The key to look up
* @return The value of the key; NULL if not present
*/
public String getVariable(String key) {
key = ValidationUtil.removeVariableIdentifier(key);
VariableValue variableValue = this.variables.get(key);
return variableValue != null ? variableValue.getValue() : null;
}
/**
* casts the value to a number
*
* @param key
* @return the double or null if it is not a number
*/
public Double getDoubleValue(String key) {
String variable = getVariable(key);
try {
if (variable != null) {
return Double.valueOf(variable);
}
} catch (NumberFormatException e) {
LOG.error(variable + " is not a Double.");
}
return null;
}
/**
* casts the value to a number
*
* @param key
* @return the double or null if it is not a number
*/
public Integer getIntegerValue(String key) {
String variable = getVariable(key);
try {
if (variable != null) {
return Integer.valueOf(variable);
}
} catch (NumberFormatException e) {
LOG.error(variable + " is not a Double.");
}
return null;
}
/**
* Handle functions
*
* @param key
* The variable name
* @param value
* The function to execute
*/
private String processFunction(String key, String value) {
String result = "";
if (ValidationUtil.isFunction(value)) {
result = FunctionHandler.executeFunction(value, this);
}
logVariable(key, value + " ==> " + result);
return result;
}
/**
* Handle a string
*
* @param key
* The variable name
* @param value
* The string value
*/
private String processString(String key, String value) {
value = evaluate(value);
logVariable(key, value);
return value;
}
public void removeVariable(String key) {
if (doLog) {
LOG.info(LogUtil.getLogMessage("Removing variable " + key));
}
this.variables.remove(key);
}
private void logVariable(String key, String value) {
if (doLog && !key.equalsIgnoreCase("_startTime")) {
LOG.info(LogUtil.getLogMessage("Setting variable " + key + " = " + value));
}
}
private static class VariableValue {
private String value;
private boolean allowOverride;
/**
* @param value
* @param allowOverride
*/
private VariableValue(String value, boolean allowOverride) {
super();
this.value = value;
this.allowOverride = allowOverride;
}
/**
* @return the value
*/
public String getValue() {
return value;
}
/**
* @{inheritDoc
*/
@Override
public String toString() {
return value;
}
}
}