package com.yahoo.dtf.actions.function; import java.util.ArrayList; import com.yahoo.dtf.actions.flowcontrol.Sequence; import com.yahoo.dtf.actions.function.Param; import com.yahoo.dtf.actions.properties.Property; import com.yahoo.dtf.actions.Action; import com.yahoo.dtf.config.Config; import com.yahoo.dtf.exception.DTFException; import com.yahoo.dtf.exception.ParseException; import com.yahoo.dtf.recorder.internal.ConfigRecorder; import com.yahoo.dtf.state.ActionState; import com.yahoo.dtf.state.DTFState; /** * @dtf.tag function * * @dtf.since 1.0 * @dtf.author Rodney Gomes * * @dtf.tag.desc Define a function that can be called from anywhere in the * subsequent XML script. This function can also be imported using * the import tag defined up ahead. * * @dtf.tag.example * <function name="func3"> * <param name="nomore" type="optional"/> * <param name="flag" default="false"/> * * <log>In func3</log> * </function> * * @dtf.tag.example * <function name="func4" export="true"> * <log>xxx</log> * <return>BLAH</return> * </function> */ public class Function extends Action { public final static String EXPORTED_FUNCTIONS_CTX = "dtf.global.functions.ctx"; /** * @dtf.attr name * @dtf.attr.desc Specifies a unique name for the function in this script * file. */ private String name = null; /** * @dtf.attr export * @dtf.attr.desc specifies if this function is to be exported so it is * accessible within any component used by this test case. * The functions are inspected to make sure that they do not * contain any references to the local or component tag. The * local tag cannot be exported because it is a functionality * of the DTFX and would allow for certain operations such as * lockcomponent, loadproperties, etc. to be executed on the * component side. */ private String export = null; public void execute() throws DTFException { throw new RuntimeException("Unsupported operation"); } private static Object _lock = new Object(); public static ArrayList<Function> getExportableFunctions() { synchronized(_lock) { ArrayList<Function> functions = (ArrayList<Function>) getGlobalContext(EXPORTED_FUNCTIONS_CTX); if ( functions == null ) { functions = new ArrayList<Function>(); registerGlobalContext(EXPORTED_FUNCTIONS_CTX, functions); } return functions; } } public void executeFunction(ArrayList<Property> args) throws DTFException { /* * Verify parameters before executing */ ArrayList<Param> params = findActions(Param.class); ActionState as = ActionState.getInstance(); DTFState current = as.getState(); DTFState state = (DTFState) current.duplicate(); for (int a = 0; a < args.size(); a++) { Property prop = args.get(a); boolean found = false; for (int p = 0; p < params.size(); p++) { Param param = params.get(p); if (prop.getName().equals(param.getName())) { found = true; break; } } if ( !found ) { getLogger().warn("Argument [" + prop.getName() + "] not being used by the function [" + getName() + "]"); } } for (int p = 0; p < params.size(); p++) { Param param = (Param)params.get(p); if (param.isRequired()) { boolean found = false; for (int i = 0; i < args.size(); i++) { Property prop = args.get(i); if (prop.getName().equals(param.getName())) { state.getConfig().setProperty(param.getName(), prop.getValue(), true); found = true; break; } } if (!found) { if (state.getConfig().getProperty(param.getName()) == null) throw new DTFException("Missing required parameter " + param); } } else if (param.isOptional()) { boolean found = false; for (int i = 0; i < args.size(); i++) { Property prop = args.get(i); if (prop.getName().equals(param.getName())) { state.getConfig().setProperty(param.getName(), prop.getValue(), true); found = true; break; } } if (!found && param.getDefault() != null) { state.getConfig().setProperty(param.getName(), param.getDefault(), true); } } } Sequence sequence = new Sequence(); sequence.addActions(children()); as.setState(state); try { Config config = current.getConfig(); // using the config recorder to make sure the events get recorded // into the parent thread! pushRecorder(new ConfigRecorder(config),null); sequence.execute(); } finally { popRecorder(); as.delState(); as.setState(current); } } public String getName() throws ParseException { return replaceProperties(name); } public void setName(String name) { this.name = name; } public boolean getExport() throws ParseException { return toBoolean("export",export); } public void setExport(String export) { this.export = export; } }