// Copyright (c) 2002-2005 Canoo Engineering AG, Switzerland. All Rights
// Reserved.
package com.canoo.webtest.extension.groovy;
import groovy.lang.Closure;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import org.apache.log4j.Logger;
import org.apache.tools.ant.RuntimeConfigurable;
import com.canoo.webtest.groovy.WebTestBuilder;
import com.canoo.webtest.steps.Step;
import com.canoo.webtest.util.FileUtil;
/**
* Wrapper class for groovy scripting.
* <p>
* @author Dierk Koenig
* @author Marc Guillemot
* @webtest.step category="Extension" name="groovy"
* description="Executes the provided Groovy script (the binding is the same for all
* groovy steps within a webtest)."
*/
public class GroovyStep extends Step
{
private static final Logger LOG = Logger.getLogger(GroovyStep.class);
private File fFile;
private Integer closureKey;
private String fText;
private Closure bodyClosure;
private boolean fReplaceProperties = false;
class DelegateForClosureBody
{
Step getStep()
{
return GroovyStep.this;
}
}
/**
* Registers the closure that will be the body of the created <groovy> step with the given wrapper.
* This is used by {@link WebTestBuilder} that makes writing WebTest tests in Groovy more... groovy.
*/
public static Integer registerBodyClosure(final Closure closure) {
final Integer key = closure.hashCode();
closuresMap_.put(key, closure);
return key;
}
private static final Map closuresMap_ = new HashMap(); // TODO: check when to remove them???
public void execute() {
// if test written in Groovy, perhaps the body has been specified as closure
// then it has to be retrieved before param verification occurs
bodyClosure = (Closure) closuresMap_.get(closureKey);
super.execute();
}
public void doExecute()
{
if (bodyClosure != null)
{
bodyClosure.setDelegate(new DelegateForClosureBody());
bodyClosure.call();
}
else
{
String script = getScript();
if (isReplaceProperties())
{
script = getProject().replaceProperties(script);
}
final GroovyInvoker invoker = new GroovyInvoker();
invoker.doExecute(this, script);
}
}
public boolean isReplaceProperties() {
return fReplaceProperties;
}
/**
* Indicates if properties should be replaced in the script (default false)
* @webtest.parameter required="no"
* default="false"
* description="Indicates if properties (${...} and #{...}) present in the script
* should be replaced by their value. Use carefully as ${...} is although the syntax for GString."
*/
public void setReplaceProperties(final boolean replaceProperties) {
fReplaceProperties = replaceProperties;
}
/**
* Gets the script code from the file or the nested content
* @return the script code
*/
private String getScript()
{
final String script;
if (fFile != null)
{
LOG.debug("Reading script from file: " + fFile);
script = FileUtil.readFileToString(fFile, this);
}
else
{
LOG.debug("Reading script from nested text");
script = fText;
}
return script;
}
protected void verifyParameters()
{
super.verifyParameters();
if (bodyClosure != null)
{
final String end = " attribute not allowed when step body is provided as closure";
paramCheck(fReplaceProperties, "\"replaceProperties\"" + end);
paramCheck(fFile != null, "\"file\"" + end);
}
else
{
paramCheck(fFile == null && fText == null,
"Either \"file\" attribute or nested groovy text must be given.");
paramCheck(fFile != null && fText != null,
"Only one of \"file\" attribute or nested groovy text may be given.");
}
}
/**
* Defines the file containing scripting code (optional).
* @param fileName Sets the name of the file containing script code.
* @webtest.parameter required="yes/no" description="The name of the file
* containing the script code. You may omit this
* parameter if you have embedded script code."
*/
public void setFile(final File fileName)
{
fFile = fileName;
}
public File getFile()
{
return fFile;
}
/**
* The script text.
* @param text Sets the value for the script variable.
* @webtest.nested.parameter required="yes/no" description="The script to
* execute. You may omit this if you use the
* attribute file."
*/
public void addText(final String text)
{
fText = text;
}
/**
* Set by {@link WebTestBuilder} to allow this task to retrieve the associated closure
* when the tests are written in Groovy.
*/
public void setClosureKey(final Integer key) {
closureKey = key;
}
}