You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by pe...@apache.org on 2006/11/23 23:51:44 UTC

svn commit: r478700 - in /ant/core/trunk/src/main/org/apache/tools/ant: taskdefs/optional/Script.java util/ScriptRunnerBase.java util/optional/ScriptRunner.java

Author: peterreilly
Date: Thu Nov 23 14:51:44 2006
New Revision: 478700

URL: http://svn.apache.org/viewvc?view=rev&rev=478700
Log:
Refactoring ScriptRunner
  * split into general non-bsf dependant part and bsf-dependant part
  * get classloader to be set outside scriptrunner
  * allow script engine to be reused in other scripts (not used in code yet)
  * add api to check if language supported (not used in code yet)
Mods from Bugzilla 40908
  * add clearing of text (not used in code yet)
  * add impl of eval  (not used in code yet)
  * use fileutils reader functionality (note: need to allow
    setting of file encoding)
    

Added:
    ant/core/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
Modified:
    ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
    ant/core/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java

Modified: ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java
URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java?view=diff&rev=478700&r1=478699&r2=478700
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/taskdefs/optional/Script.java Thu Nov 23 14:51:44 2006
@@ -21,6 +21,7 @@
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Task;
 import org.apache.tools.ant.util.optional.ScriptRunner;
+import org.apache.tools.ant.util.ScriptRunnerBase;
 import org.apache.tools.ant.types.Path;
 import org.apache.tools.ant.types.Reference;
 
@@ -43,7 +44,7 @@
      * @exception BuildException if something goes wrong with the build
      */
     public void execute() throws BuildException {
-        ScriptRunner runner = new ScriptRunner();
+        ScriptRunnerBase runner = new ScriptRunner();
         if (language != null) {
             runner.setLanguage(language);
         }
@@ -54,7 +55,9 @@
             runner.addText(text);
         }
         if (classpath != null) {
-            runner.setClasspath(classpath);
+            runner.setScriptClassLoader(
+                getProject().createClassLoader(
+                    getClass().getClassLoader(), classpath));
         }
         if (setBeans) {
             runner.bindToComponent(this);

Added: ant/core/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java?view=auto&rev=478700
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java (added)
+++ ant/core/trunk/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java Thu Nov 23 14:51:44 2006
@@ -0,0 +1,283 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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 org.apache.tools.ant.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Project;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * This is a common abstract base case for script runners.
+ * These classes need to implement executeScript, evalulateScript
+ * and supportsLanguage.
+ */
+public abstract class ScriptRunnerBase {
+    /** Whether to keep the engine between calls to execute/eval */
+    private boolean keepEngine = false;
+
+    /** Script language */
+    private String language;
+
+    /** Script content */
+    private String script = "";
+
+    /** Project this runner is used in */
+    private Project project;
+
+    /** Classloader to be used when running the script. */
+    private ClassLoader scriptLoader;
+
+    /** Beans to be provided to the script */
+    private Map beans = new HashMap();
+
+    /**
+     * Add a list of named objects to the list to be exported to the script
+     *
+     * @param dictionary a map of objects to be placed into the script context
+     *        indexed by String names.
+     */
+    public void addBeans(Map dictionary) {
+        for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            try {
+                Object val = dictionary.get(key);
+                addBean(key, val);
+            } catch (BuildException ex) {
+                // The key is in the dictionary but cannot be retrieved
+                // This is usually due references that refer to tasks
+                // that have not been taskdefed in the current run.
+                // Ignore
+            }
+        }
+    }
+
+    /**
+     * Add a single object into the script context.
+     *
+     * @param key the name in the context this object is to stored under.
+     * @param bean the object to be stored in the script context.
+     */
+    public void addBean(String key, Object bean) {
+        boolean isValid = key.length() > 0
+            && Character.isJavaIdentifierStart(key.charAt(0));
+
+        for (int i = 1; isValid && i < key.length(); i++) {
+            isValid = Character.isJavaIdentifierPart(key.charAt(i));
+        }
+
+        if (isValid) {
+            beans.put(key, bean);
+        }
+    }
+
+    /**
+     * Get the beans used for the script.
+     * @return the map of beans.
+     */
+    protected Map getBeans() {
+        return beans;
+    }
+
+    /**
+     * Do the work.
+     * @param execName the name that will be passed to BSF for this script
+     *        execution.
+     */
+    public abstract void executeScript(String execName);
+
+    /**
+     * Evalulate the script.
+     * @param execName the name that will be passed to BSF for this script
+     *        execution.
+     * @return the result of evalulating the script.
+     */
+    public abstract Object evalulateScript(String execName);
+
+    /**
+     * Check if a script engine can be created for
+     * this language.
+     * @return true if a script engine can be created, false
+     *              otherwise.
+     */
+    public abstract boolean supportsLanguage();
+
+    /**
+     * Defines the language (required).
+     * @param language the scripting language name for the script.
+     */
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    /**
+     * Get the script language
+     * @return the script language
+     */
+    public String getLanguage() {
+        return language;
+    }
+
+    /**
+     * Set the script classloader.
+     * @param classLoader the classloader to use.
+     */
+    public void setScriptClassLoader(ClassLoader classLoader) {
+        this.scriptLoader = classLoader;
+    }
+
+    /**
+     * Get the classloader used to load the script engine.
+     * @return the classloader.
+     */
+    protected ClassLoader getScriptClassLoader() {
+        return scriptLoader;
+    }
+
+    /**
+     * Whether to keep the script engine between calls.
+     * @param keepEngine if true, keep the engine.
+     */
+    public void setKeepEngine(boolean keepEngine) {
+        this.keepEngine = keepEngine;
+    }
+
+    /**
+     * Get the keep engine attribute.
+     * @return the attribute.
+     */
+    public boolean getKeepEngine() {
+        return keepEngine;
+    }
+
+    /**
+     * Load the script from an external file; optional.
+     * @param file the file containing the script source.
+     */
+    public void setSrc(File file) {
+        if (!file.exists()) {
+            throw new BuildException("file " + file.getPath() + " not found.");
+        }
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader(file));
+            script += FileUtils.readFully(in);
+        } catch (IOException ex) {
+            throw new BuildException(ex);
+        } finally {
+            FileUtils.close(in);
+        }
+    }
+
+    /**
+     * Set the script text.
+     *
+     * @param text a component of the script text to be added.
+     */
+    public void addText(String text) {
+        this.script += text;
+    }
+
+    /**
+     * Get the current script text content.
+     * @return the script text.
+     */
+    public String getScript() {
+        return script;
+    }
+
+    /**
+     * Clear the current script text content.
+     */
+    public void clearScript() {
+        this.script = "";
+    }
+
+    /**
+     * Bind the runner to a project component.
+     * Properties, targets and references are all added as beans;
+     * project is bound to project, and self to the component.
+     * @param component to become <code>self</code>
+     */
+    public void bindToComponent(ProjectComponent component) {
+        project = component.getProject();
+        addBeans(project.getProperties());
+        addBeans(project.getUserProperties());
+        addBeans(project.getTargets());
+        addBeans(project.getReferences());
+        addBean("project", project);
+        addBean("self", component);
+    }
+
+    /**
+     * Bind the runner to a project component.
+     * The project and self are the only beans set.
+     * @param component to become <code>self</code>
+     */
+    public void bindToComponentMinimum(ProjectComponent component) {
+        project = component.getProject();
+        addBean("project", project);
+        addBean("self", component);
+    }
+
+    /**
+     * Check if the language attribute is set.
+     * @throws BuildException if it is not.
+     */
+    protected void checkLanguage() {
+        if (language == null) {
+            throw new BuildException(
+                "script language must be specified");
+        }
+    }
+
+    /**
+     * Replace the current context classloader with the
+     * script context classloader.
+     * @return the current context classloader.
+     */
+    protected ClassLoader replaceContextLoader() {
+        ClassLoader origContextClassLoader =
+            Thread.currentThread().getContextClassLoader();
+        if (getScriptClassLoader() == null) {
+            setScriptClassLoader(getClass().getClassLoader());
+        }
+        Thread.currentThread().setContextClassLoader(getScriptClassLoader());
+        return origContextClassLoader;
+    }
+
+    /**
+     * Restore the context loader with the original context classloader.
+     *
+     * script context loader.
+     * @param origLoader the original context classloader.
+     */
+    protected void restoreContextLoader(ClassLoader origLoader) {
+        Thread.currentThread().setContextClassLoader(
+                 origLoader);
+    }
+
+}

Modified: ant/core/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java
URL: http://svn.apache.org/viewvc/ant/core/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java?view=diff&rev=478700&r1=478699&r2=478700
==============================================================================
--- ant/core/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java (original)
+++ ant/core/trunk/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java Thu Nov 23 14:51:44 2006
@@ -17,35 +17,22 @@
  */
 package org.apache.tools.ant.util.optional;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
 import org.apache.bsf.BSFException;
 import org.apache.bsf.BSFManager;
+import org.apache.bsf.BSFEngine;
 
 import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.ProjectComponent;
-import org.apache.tools.ant.Project;
-
-import org.apache.tools.ant.util.FileUtils;
 
-import java.util.Map;
-import java.util.HashMap;
 import java.util.Iterator;
-import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.ScriptRunnerBase;
 
 /**
  * This class is used to run BSF scripts
  *
  */
-public class ScriptRunner {
-
-    // 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.
+public class ScriptRunner extends ScriptRunnerBase {
+    // Register Groovy ourselves, since BSF did not
+    // natively support it in versions previous to 1.2.4.
     static {
         BSFManager.registerScriptingEngine(
             "groovy",
@@ -53,58 +40,30 @@
             new String[] {"groovy", "gy"});
     }
 
-    /** Script language */
-    private String language;
-
-    /** Script content */
-    private String script = "";
-
-    /** Beans to be provided to the script */
-    private Map beans = new HashMap();
-
-    /** Classpath to be used when running the script. */
-    private Path classpath = null;
-
-    /** Project this runner is used in */
-    private Project project = null;
+    private BSFEngine  engine;
+    private BSFManager manager;
 
     /**
-     * Add a list of named objects to the list to be exported to the script
-     *
-     * @param dictionary a map of objects to be placed into the script context
-     *        indexed by String names.
+     * Check if bsf supports the language.
+     * @return true if bsf can create an engine for this language.
      */
-    public void addBeans(Map dictionary) {
-        for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
-            String key = (String) i.next();
-            try {
-                Object val = dictionary.get(key);
-                addBean(key, val);
-            } catch (BuildException ex) {
-                // The key is in the dictionary but cannot be retrieved
-                // This is usually due references that refer to tasks
-                // that have not been taskdefed in the current run.
-                // Ignore
-            }
+    public boolean supportsLanguage() {
+        if (manager != null) {
+            return true;
         }
-    }
-
-    /**
-     * Add a single object into the script context.
-     *
-     * @param key the name in the context this object is to stored under.
-     * @param bean the object to be stored in the script context.
-     */
-    public void addBean(String key, Object bean) {
-        boolean isValid = key.length() > 0
-            && Character.isJavaIdentifierStart(key.charAt(0));
-
-        for (int i = 1; isValid && i < key.length(); i++) {
-            isValid = Character.isJavaIdentifierPart(key.charAt(i));
-        }
-
-        if (isValid) {
-            beans.put(key, bean);
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
+        try {
+            BSFManager m = createManager();
+            BSFEngine e =
+                engine != null
+                ? engine
+                : m.loadScriptingEngine(getLanguage());
+            return e != null;
+        } catch (Exception ex) {
+            return false;
+        } finally {
+            restoreContextLoader(origLoader);
         }
     }
 
@@ -117,139 +76,99 @@
      * @exception BuildException if someting goes wrong exectuing the script.
      */
     public void executeScript(String execName) throws BuildException {
-        if (language == null) {
-            throw new BuildException("script language must be specified");
-        }
-
-        ClassLoader origContextClassLoader =
-            Thread.currentThread().getContextClassLoader();
-        ClassLoader scriptLoader = getClass().getClassLoader();
-        if (classpath != null && project != null) {
-            scriptLoader = project.createClassLoader(
-                scriptLoader, classpath);
-        }
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
         try {
-            Thread.currentThread().setContextClassLoader(scriptLoader);
-            BSFManager manager = new BSFManager ();
-            manager.setClassLoader(scriptLoader);
-
-            for (Iterator i = beans.keySet().iterator(); i.hasNext();) {
-                String key = (String) i.next();
-                Object value = beans.get(key);
-                if (value != null) {
-                    manager.declareBean(key, value, value.getClass());
-                } else {
-                    // BSF uses a hashtable to store values
-                    // so cannot declareBean with a null value
-                    // So need to remove any bean of this name as
-                    // that bean should not be visible
-                    manager.undeclareBean(key);
-                }
-            }
-
+            BSFManager m = createManager();
+            declareBeans(m);
             // execute the script
-            manager.exec(language, execName, 0, 0, script);
-        } catch (BSFException be) {
-            Throwable t = be;
-            Throwable te = be.getTargetException();
-            if (te != null) {
-                if  (te instanceof BuildException) {
-                    throw (BuildException) te;
-                } else {
-                    t = te;
-                }
+            if (engine == null) {
+                m.exec(getLanguage(), execName, 0, 0, getScript());
+            } else {
+                engine.exec(execName, 0, 0, getScript());
             }
-            throw new BuildException(t);
+        } catch (BSFException be) {
+            throwBuildException(be);
         } finally {
-             Thread.currentThread().setContextClassLoader(
-                 origContextClassLoader);
+            restoreContextLoader(origLoader);
         }
     }
 
     /**
-     * Defines the language (required).
-     *
-     * @param language the scripting language name for the script.
-     */
-    public void setLanguage(String language) {
-        this.language = language;
-    }
-
-    /**
-     * Get the script language
-     *
-     * @return the script language
-     */
-    public String getLanguage() {
-        return language;
-    }
-
-    /**
-     * Set the class path to be used.
-     * @param classpath the path to use.
-     */
-    public void setClasspath(Path classpath) {
-        this.classpath = classpath;
-    }
-
-    /**
-     * Load the script from an external file ; optional.
+     * Do the work.
      *
-     * @param file the file containing the script source.
+     * @param execName the name that will be passed to BSF for this script
+     *        execution.
+     * @return the result of the evalulation
+     * @exception BuildException if someting goes wrong exectuing the script.
      */
-    public void setSrc(File file) {
-        if (!file.exists()) {
-            throw new BuildException("file " + file.getPath() + " not found.");
-        }
-
-        int count = (int) file.length();
-        byte[] data = new byte[count];
-        FileInputStream inStream = null;
+    public Object evalulateScript(String execName)
+        throws BuildException {
+        checkLanguage();
+        ClassLoader origLoader = replaceContextLoader();
         try {
-            inStream = new FileInputStream(file);
-            inStream.read(data);
-        } catch (IOException e) {
-            throw new BuildException(e);
+            BSFManager m = createManager();
+            declareBeans(m);
+            // execute the script
+            if (engine == null) {
+                return m.eval(getLanguage(), execName, 0, 0, getScript());
+            } else {
+                return engine.eval(execName, 0, 0, getScript());
+            }
+        } catch (BSFException be) {
+            throwBuildException(be);
+            // NotReached
+            return null;
         } finally {
-            FileUtils.close(inStream);
+            restoreContextLoader(origLoader);
         }
-
-        script += new String(data);
     }
 
     /**
-     * Set the script text.
-     *
-     * @param text a component of the script text to be added.
+     * Throw a buildException in place of a BSFException.
+     * @param be BSFException to convert.
+     * @throws BuildException the conveted exception.
      */
-    public void addText(String text) {
-        this.script += text;
+    private void throwBuildException(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);
     }
 
-    /**
-     * Bind the runner to a project component.
-     * Properties, targets and references are all added as beans;
-     * project is bound to project, and self to the component.
-     * @param component to become <code>self</code>
-     */
-    public void bindToComponent(ProjectComponent component) {
-        project = component.getProject();
-        addBeans(project.getProperties());
-        addBeans(project.getUserProperties());
-        addBeans(project.getTargets());
-        addBeans(project.getReferences());
-        addBean("project", project);
-        addBean("self", component);
+    private void declareBeans(BSFManager m) throws BSFException {
+        for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            Object value = getBeans().get(key);
+            if (value != null) {
+                m.declareBean(key, value, value.getClass());
+            } else {
+                // BSF uses a hashtable to store values
+                // so cannot declareBean with a null value
+                // So need to remove any bean of this name as
+                // that bean should not be visible
+                m.undeclareBean(key);
+            }
+        }
     }
 
-    /**
-     * Bind the runner to a project component.
-     * The project and self are the only beans set.
-     * @param component to become <code>self</code>
-     */
-    public void bindToComponentMinimum(ProjectComponent component) {
-        project = component.getProject();
-        addBean("project", project);
-        addBean("self", component);
+    private BSFManager createManager() throws BSFException {
+        if (manager != null) {
+            return manager;
+        }
+        BSFManager m = new BSFManager();
+        m.setClassLoader(getScriptClassLoader());
+        if (getKeepEngine()) {
+            BSFEngine e = manager.loadScriptingEngine(getLanguage());
+            this.manager = m;
+            this.engine  = e;
+        }
+        return m;
     }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org