/** * Copyright 2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.xceptance.xlt.common.util.bsh; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.eclipse.jdt.annotation.Nullable; import bsh.EvalError; import bsh.Interpreter; import com.gargoylesoftware.htmlunit.util.NameValuePair; import com.xceptance.xlt.api.data.GeneralDataProvider; import com.xceptance.xlt.api.util.XltLogger; import com.xceptance.xlt.api.util.XltProperties; /** * Our implementation of the param interpreter, it will set some default data objects for later use, such as NOW and * RANDOM ect. */ public class ParameterInterpreter extends Interpreter { @Nullable private XltProperties properties; private static final long serialVersionUID = -6490310093160560291L; /** * The pattern to get the inserted param or commands from strings, such as ${bar = System.currentTimeMillis()} */ private final static Pattern parameterPattern = Pattern.compile("\\$\\{([^$]*)\\}"); /** * Processes dynamic data on the input and use the set interpreter and its state. * * @param testCase * the currently active testcase, needed for proper property lookup * @param input * the input to process * @return a processed string or the same, if nothing to process */ public ParameterInterpreter(final XltProperties properties, final GeneralDataProvider dataProvider) { super(); XltLogger.runTimeLogger.debug("Creating new Instance"); try { this.set("NOW", new ParameterInterpreterNow()); this.set("RANDOM", new ParameterInterpreterRandom()); this.set("DATA", dataProvider); this.set("DATE", new Date()); this.properties = properties; } catch (final EvalError e) { // nothing should happen here, we just add context } } /** * Just setup our interpreter and it will be filled with default data objects. */ public void set(final NameValuePair nvp) throws EvalError { final String name = nvp.getName(); final String value = nvp.getValue(); if (name != null) { XltLogger.runTimeLogger.debug(addVariableMessage(name, value)); this.set(name, value); } else { XltLogger.runTimeLogger.debug("Failed to add variable: \"" + name + "\" = \"" + value + "\", because its identifier was 'null'"); } } /** * Maps input on predefined value. The value can be defined dynamically during runtime or in the properties. The * lookup works the following way and breaks, when a value is found. * <ol> * <li>Map key on dynamic runtime data</li> * <li>Map key on properties</li> * </ol> * * @param input * : key * @return value reference, or if nothing was found the input itself */ @Nullable public String processDynamicData(final String input) { String result = null; if (input != null) { result = input; final List<String> params = getPatternMatches(input); if (!params.isEmpty()) { for (final String param : params) { if (param.trim().length() != 0) { try { final Object evalResult = this.eval(param); if (evalResult != null) { result = StringUtils.replaceOnce(result, "${" + param + "}", evalResult.toString()); } } catch (final EvalError e) { XltLogger.runTimeLogger.warn(MessageFormat.format("Unable to process dynamic parameter {0}", "${" + param + "}"), e); } // first try to map it to a property if a test case is set otherwise ask the properties directly if (result.equals(input)) { final String propertyValue = getPropertyValue(param); if (propertyValue != null) { result = StringUtils.replaceOnce(result, "${" + param + "}", propertyValue); } } // look into variables map } } } } return result; } protected List<String> getPatternMatches(final String input) { final List<String> result = new ArrayList<String>(); final Matcher matcher = parameterPattern.matcher(input); while (matcher.find()) { result.add(matcher.group(1)); } return result; } @Nullable protected String getPropertyValue(final String propertyName) { final String propertyValue = properties.getProperty(propertyName); return propertyValue; } protected String addVariableMessage(final String name, final String value) { final String message = MessageFormat.format("Adding Variables: \"{0}\" = \"{1}\"", name, value); return message; } }