/* * 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; import java.util.Date; import java.util.HashMap; import com.slamd.job.JobClass; import com.slamd.job.UnableToRunException; import com.slamd.parameter.BooleanParameter; import com.slamd.parameter.FileURLParameter; import com.slamd.parameter.InvalidValueException; import com.slamd.parameter.MultiLineTextParameter; import com.slamd.parameter.Parameter; import com.slamd.parameter.ParameterList; import com.slamd.parameter.PlaceholderParameter; import com.slamd.stat.StatTracker; import com.slamd.scripting.engine.ScriptException; import com.slamd.scripting.engine.ScriptParser; /** * This class defines a SLAMD job that will perform its work by executing a * the instructions in a script file. * * * @author Neil A. Wilson */ public class ScriptedJobClass extends JobClass { /** * The name of the job parameter that indicates whether the script should be * executed in debug mode. */ public static final String DEBUG_PARAMETER_NAME = "debug_mode"; /** * The name of the job parameter that defines the script file to use. */ public static final String SCRIPT_FILE_PARAMETER_NAME = "script_file"; /** * The name of the job parameter that allows the user to pass arguments to the * script. */ public static final String SCRIPT_ARGUMENTS_PARAMETER_NAME = "script_arguments"; // Indicates whether the script should be executed in debug mode. private static boolean debugScript; // The map containing the set of script arguments provided when the job was // scheduled. private static HashMap<String,String> scriptArgumentHash; // The lines contained in the script file to be executed. private static String[] scriptFileLines; // The script parser used to handle all interaction with the script file. private ScriptParser parser; /** * Creates a new instance of this job thread. This constructor * does not need to do anything other than invoke the constructor * for the superclass. */ public ScriptedJobClass() { super(); } /** * {@inheritDoc} */ @Override() public String getJobName() { return "SLAMD Script"; } /** * {@inheritDoc} */ @Override() public String getShortDescription() { return "Execute a user-provided SLAMD script"; } /** * {@inheritDoc} */ @Override() public String[] getLongDescription() { return new String[] { "This job can be used to execute a user-provided SLAMD script." }; } /** * {@inheritDoc} */ @Override() public String getJobCategoryName() { return "Scripting"; } /** * {@inheritDoc} */ @Override() public ParameterList getParameterStubs() { PlaceholderParameter placeholder = new PlaceholderParameter(); BooleanParameter debugParameter = new BooleanParameter(DEBUG_PARAMETER_NAME, "Execute in Debug Mode", "Indicates whether the script should be " + "executed in debug mode. This will be much " + "less efficient, but can be useful for " + "debugging problems that arise.", false); FileURLParameter scriptFileParameter = new FileURLParameter(SCRIPT_FILE_PARAMETER_NAME, "Script File URL", "The URL to the file containing the script to " + "execute. This URL may reference the file " + "location using http, https, ftp, or file.", null, true); MultiLineTextParameter scriptArgumentsParameter = new MultiLineTextParameter(SCRIPT_ARGUMENTS_PARAMETER_NAME, "Script Arguments", "A set of arguments that may be provided " + "to the script that can customize the " + "way that it behaves. The arguments " + "should be provided one per line in the " + "format \"name=value\".", new String[0], false); scriptArgumentsParameter.setVisibleColumns(80); scriptArgumentsParameter.setVisibleRows(10); Parameter[] parameterArray = new Parameter[] { placeholder, scriptFileParameter, scriptArgumentsParameter, debugParameter }; return new ParameterList(parameterArray); } /** * {@inheritDoc} */ @Override() public StatTracker[] getStatTrackerStubs(String clientID, String threadID, int collectionInterval) { return new StatTracker[0]; } /** * {@inheritDoc} */ @Override() public StatTracker[] getStatTrackers() { // If the script has been run, then get the stat trackers associated with // it. Otherwise, just return an empty set. if (this.parser == null) { return new StatTracker[0]; } else { return parser.getStatTrackers(); } } /** * {@inheritDoc} */ @Override() public void validateJobInfo(int numClients, int threadsPerClient, int threadStartupDelay, Date startTime, Date stopTime, int duration, int collectionInterval, ParameterList parameters) throws InvalidValueException { // Retrieve and parse the script file to ensure that it is available and can // be parsed properly. If not, then throw an exception to let the end // user know what the problem is. FileURLParameter fp = parameters.getFileURLParameter(SCRIPT_FILE_PARAMETER_NAME); try { scriptFileLines = fp.getFileLines(); } catch (Exception e) { throw new InvalidValueException("Unable to retrieve the script file: " + e, e); } try { parser = new ScriptParser(); parser.setScriptLines(scriptFileLines); parser.parse(); } catch (ScriptException se) { throw new InvalidValueException("An error occurred while parsing the " + "script: " + se.getMessage(), se); } } /** * {@inheritDoc} */ @Override() public void initializeClient(String clientID, ParameterList parameters) throws UnableToRunException { FileURLParameter fp = parameters.getFileURLParameter(SCRIPT_FILE_PARAMETER_NAME); if (fp != null) { try { scriptFileLines = fp.getFileLines(); } catch (Exception e) { e.printStackTrace(); } } scriptArgumentHash = new HashMap<String,String>(); MultiLineTextParameter mtp = parameters.getMultiLineTextParameter(SCRIPT_ARGUMENTS_PARAMETER_NAME); if (mtp != null) { try { String[] lines = mtp.getNonBlankLines(); for (int i=0; i < lines.length; i++) { int equalPos = lines[i].indexOf('='); if (equalPos > 0) { String name = lines[i].substring(0, equalPos); String value = lines[i].substring(equalPos+1); scriptArgumentHash.put(name.toLowerCase(), value); } } } catch (Exception e) { e.printStackTrace(); } } debugScript = false; BooleanParameter bp = parameters.getBooleanParameter(DEBUG_PARAMETER_NAME); if (bp != null) { debugScript = bp.getBooleanValue(); } } /** * {@inheritDoc} */ @Override() public void initializeThread(String clientID, String threadID, int collectionInterval, ParameterList parameters) throws UnableToRunException { // Read and parse the script file. try { parser = new ScriptParser(); parser.setScriptLines(scriptFileLines); parser.setScriptArguments(scriptArgumentHash); parser.parse(); } catch (ScriptException se) { throw new UnableToRunException("Unable to parse the script: " + se, se); } } /** * {@inheritDoc} */ @Override() public void runJob() { // Execute the instructions contained in the script. try { if (debugScript) { parser.debugExecute(this); } else { parser.execute(this); } } catch (Exception e) { logMessage("Exception while executing script: " + stackTraceToString(e)); indicateStoppedDueToError(); } } }