[EMAIL PROTECTED] wrote:

So the task should do compiling and taskdefing?
Maybe caching the compiled data?

Jan


The languages do the compiling (Both beanshell and groovy currently use
asm - http://asm.objectweb.org) and return a class object when the BSF
eval method is called.

The task itself is very small:

Peter






-----Original Message-----
From: Peter Reilly [mailto:[EMAIL PROTECTED]
Sent: Monday, February 16, 2004 10:21 AM
To: Ant Developers List
Subject: [Fwd: [New task] scripttypedef (or refectdef)]










package org.apache.tools.ant.taskdefs.optional;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.apache.bsf.BSFManager;
import org.apache.bsf.BSFException;

import org.apache.tools.ant.AntTypeDefinition;
import org.apache.tools.ant.taskdefs.DefBase;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ComponentHelper;
import org.apache.tools.ant.ProjectHelper;


/**
 * Class to define an ant definition using a script that
 * can return a class that is a normal ant task/datatype.
 * If the language is beanshell it must be 2.0 or higher.
 * The other scripting currently known to work is
 * groovy (1.0beta3).
 * <p>
 * Note that if there is anything incorrect with the script
 * the warning message is quite cryptic.
 * </p>
 * This class is based in part on o.a.t.ant.util.ScriptRunner.
 * The main difference is that it does not define
 * beans. This is for three reasons:
 * <ol>
 * <li>The definition may be used in another project.</li>
 * <li>It should be possible to convert to java later.</li>
 * </ol>
 *
 * @author  Peter Reilly
 * @since   Ant 1.7
 */
public class ScriptTypeDef extends DefBase {
    // Register Groovy ourselves, since BSF does not
    // natively support it (yet).
    // This "hack" can be removed once BSF has been
    // modified to support Groovy or more dynamic
    // registration.
    static {
        BSFManager.registerScriptingEngine(
            "groovy",
            "org.codehaus.groovy.bsf.GroovyEngine",
            new String[] {"groovy", "gy"});
    }

    private String language;
    private File   src;
    private String text;
    private String eval;
    private String name;

    /**
     * Defines the language (required).
     *
     * @param language the scripting language name for the script.
     */
    public void setLanguage(String language) {
        this.language = language;
    }

    /**
     * A string to evaluate.
     *
     * @param eval a string to evaluate.
     */
    public void setEval(String eval) {
        this.eval = eval;
    }

    /**
     * Load the script from an external file ; optional.
     *
     * @param src the file containing the script source.
     */
    public void setSrc(File src) {
        this.src = src;
    }

    /**
     * Set the script text.
     *
     * @param text a component of the script text to be added.
     */
    public void addText(String text) {
        this.text = getProject().replaceProperties(text);
    }

    /**
     * Name of the definition
     * @param name the name of the definition
     */
    public void setName(String name) {
        this.name = name;
    }

    private boolean equalsHandleNull(Object a, Object b) {
        if (a == null) {
            return b == null;
        }
        if (b == null) {
            return false;
        }
        return a.equals(b);
    }

    /**
     * define the beanshell definition.
     * check the attributes, get the class been defined and
     * set the definition.
     */
    public void execute() {
        if (name == null) {
            throw new BuildException("Missing attribute name");
        }
        if (text == null && src == null) {
            throw new BuildException("Missing script or file");
        }
        if (language == null) {
            throw new BuildException("Missing language");
        }

        ComponentHelper helper =
            ComponentHelper.getComponentHelper(getProject());

        String namespacedName = ProjectHelper.genComponentName(getURI(), name);

        // Check if definition already present due to antcall type behaviour
        AntTypeDefinition oldDef = helper.getDefinition(namespacedName);
        if (oldDef != null && oldDef instanceof ScriptTypeDefinition) {
            // See if the data is the same.
            ScriptTypeDef other = ((ScriptTypeDefinition) oldDef).getOwner();
            if (equalsHandleNull(src, other.src)
                && equalsHandleNull(text, other.text)
                && equalsHandleNull(eval, other.eval)
                && equalsHandleNull(language, other.language)) {
                return; // Ingore new definition as it is the same
            }
        }

        // Currently neither beanshell 2.0beta or groovy 1.0
        // look at BSFManager#setClassLoader(),
        // the following will work for groovy but not for beanshell
        
        ClassLoader currentLoader =
            Thread.currentThread().getContextClassLoader();
        BSFManager manager = new BSFManager();
        try {
            ClassLoader cl = createLoader();
            Thread.currentThread().setContextClassLoader(cl);
            manager.setClassLoader(cl);
            Object o = manager.eval(language, "ant", 0, 0, getScript());

            if (!(o instanceof Class)) {
                throw new BuildException("The object should be a Class");
            }
            Class cl = (Class) o;
            ScriptTypeDefinition def = new ScriptTypeDefinition();
            def.setName(ProjectHelper.genComponentName(getURI(), name));
            def.setClassName(cl.getName());
            def.setClass(cl);
            def.setOwner(this);
            ComponentHelper.getComponentHelper(getProject())
                .addDataTypeDefinition(def);
        } catch (BSFException be) {
            Throwable t = be;
            Throwable te = be.getTargetException();
            if (te != null) {
                if  (te instanceof BuildException) {
                    throw (BuildException) te;
                } else {
                    t = te;
                }
            }
            throw new BuildException(t);
       } catch (BuildException ex) {
            throw ex;
       } catch (Throwable t) {
           throw new BuildException(t);
       } finally {
           manager.terminate();
           try {
               Thread.currentThread().setContextClassLoader(currentLoader);
           } catch (Throwable t) {
               // Ignore
           }
           
       }
    }

    private static class ScriptTypeDefinition extends AntTypeDefinition {
        private ScriptTypeDef owner;
        private void setOwner(ScriptTypeDef owner) {
            this.owner = owner;
        }
        private ScriptTypeDef getOwner() {
            return owner;
        }
    }

    private String getFileString(File file) {
        if (!file.exists()) {
            throw new BuildException("file " + file.getPath() + " not found.");
        }

        int count = (int) file.length();
        byte[] data = new byte[count];

        try {
            FileInputStream inStream = new FileInputStream(file);
            inStream.read(data);
            inStream.close();
        } catch (IOException e) {
            throw new BuildException(e);
        }

        return new String(data);
    }

    private String getScript() {
        String ret = "";
        if (src != null) {
            ret = getFileString(src);
        }
        if (text != null) {
            ret = ret + text;
        }
        if (eval != null) {
            ret = ret + eval;
        }
        return ret;
    }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to