@@ -67,7 +67,7 @@ public class ScriptDef extends DefBase { | |||
/** | |||
* Set the project. | |||
* @param project the project that this def belows to. | |||
* @param project the project that this definition belongs to. | |||
*/ | |||
public void setProject(Project project) { | |||
super.setProject(project); | |||
@@ -237,7 +237,6 @@ public class ScriptDef extends DefBase { | |||
+ "attributes"); | |||
} | |||
nestedElementMap.put(nestedElement.name, nestedElement); | |||
} | |||
@@ -367,6 +366,15 @@ public class ScriptDef extends DefBase { | |||
helper.setLanguage(language); | |||
} | |||
/** | |||
* Defines the language (required). | |||
* | |||
* @param language the scripting language name for the script. | |||
*/ | |||
public void setCompiled(boolean compiled) { | |||
helper.setCompiled(compiled); | |||
} | |||
/** | |||
* Load the script from an external file ; optional. | |||
* | |||
@@ -376,6 +384,15 @@ public class ScriptDef extends DefBase { | |||
helper.setSrc(file); | |||
} | |||
/** | |||
* Set the encoding of the script from an external file ; optional. | |||
* | |||
* @param encoding the encoding of the file containing the script source. | |||
*/ | |||
public void setEncoding(String encoding) { | |||
helper.setEncoding(encoding); | |||
} | |||
/** | |||
* Set the script text. | |||
* | |||
@@ -394,4 +411,3 @@ public class ScriptDef extends DefBase { | |||
helper.add(resource); | |||
} | |||
} | |||
@@ -19,12 +19,13 @@ package org.apache.tools.ant.util; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.io.Reader; | |||
import java.io.UnsupportedEncodingException; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.Map; | |||
@@ -34,6 +35,8 @@ import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.ProjectComponent; | |||
import org.apache.tools.ant.types.Resource; | |||
import org.apache.tools.ant.types.ResourceCollection; | |||
import org.apache.tools.ant.types.resources.PropertyResource; | |||
import org.apache.tools.ant.types.resources.StringResource; | |||
/** | |||
* This is a common abstract base case for script runners. | |||
@@ -51,6 +54,11 @@ public abstract class ScriptRunnerBase { | |||
/** Script content */ | |||
private String script = ""; | |||
private String encoding; | |||
/** Enable script compilation. */ | |||
private boolean compiled; | |||
/** Project this runner is used in */ | |||
private Project project; | |||
@@ -186,8 +194,36 @@ public abstract class ScriptRunnerBase { | |||
return keepEngine; | |||
} | |||
/** | |||
* Whether to use script compilation if available. | |||
* @since Ant 1.10.1 | |||
* @param compiled if true, compile the script if possible. | |||
*/ | |||
public final void setCompiled(boolean compiled) { | |||
this.compiled = compiled; | |||
} | |||
/** | |||
* Get the compiled attribute. | |||
* @since Ant 1.10.1 | |||
* @return the attribute. | |||
*/ | |||
public final boolean getCompiled() { | |||
return compiled; | |||
} | |||
/** | |||
* Set encoding of the script from an external file; optional. | |||
* @since Ant 1.10.1 | |||
* @param encoding encoding of the external file containing the script source. | |||
*/ | |||
public void setEncoding(String encoding) { | |||
this.encoding = encoding; | |||
} | |||
/** | |||
* Load the script from an external file; optional. | |||
* @since Ant 1.10.1 | |||
* @param file the file containing the script source. | |||
*/ | |||
public void setSrc(File file) { | |||
@@ -195,12 +231,19 @@ public abstract class ScriptRunnerBase { | |||
if (!file.exists()) { | |||
throw new BuildException("file " + filename + " not found."); | |||
} | |||
InputStream in = null; | |||
try { | |||
readSource(new FileReader(file), filename); | |||
in = new FileInputStream(file); | |||
} catch (FileNotFoundException e) { | |||
//this can only happen if the file got deleted a short moment ago | |||
throw new BuildException("file " + filename + " not found."); | |||
} | |||
try { | |||
readSource(in, filename); | |||
} finally { | |||
FileUtils.close(in); | |||
} | |||
} | |||
/** | |||
@@ -208,19 +251,25 @@ public abstract class ScriptRunnerBase { | |||
* @param reader the reader; this is closed afterwards. | |||
* @param name the name to use in error messages | |||
*/ | |||
private void readSource(Reader reader, String name) { | |||
BufferedReader in = null; | |||
private void readSource(InputStream in, String name) { | |||
Reader reader = null; | |||
try { | |||
in = new BufferedReader(reader); | |||
script += FileUtils.safeReadFully(in); | |||
if (null == encoding) { | |||
reader = new InputStreamReader(in); | |||
} else { | |||
reader = new InputStreamReader(in, encoding); | |||
} | |||
reader = new BufferedReader(reader); | |||
script += FileUtils.safeReadFully(reader); | |||
} catch(UnsupportedEncodingException e) { | |||
throw new BuildException("Failed to decode " + name + " with encoding " + encoding, e); | |||
} catch (IOException ex) { | |||
throw new BuildException("Failed to read " + name, ex); | |||
} finally { | |||
FileUtils.close(in); | |||
FileUtils.close(reader); | |||
} | |||
} | |||
/** | |||
* Add a resource to the source list. | |||
* @since Ant 1.7.1 | |||
@@ -228,6 +277,20 @@ public abstract class ScriptRunnerBase { | |||
* @throws BuildException if the resource cannot be read | |||
*/ | |||
public void loadResource(Resource sourceResource) { | |||
if(sourceResource instanceof StringResource) { | |||
// Note: StringResource uses UTF-8 by default to encode/decode, not the default platform encoding | |||
script += ((StringResource) sourceResource).getValue(); | |||
return; | |||
} | |||
if(sourceResource instanceof PropertyResource) { | |||
script += ((PropertyResource) sourceResource).getValue(); | |||
return; | |||
} | |||
// Concat resource | |||
// FileResource : OK for default encoding | |||
String name = sourceResource.toLongString(); | |||
InputStream in = null; | |||
try { | |||
@@ -238,7 +301,12 @@ public abstract class ScriptRunnerBase { | |||
throw new BuildException( | |||
"Failed to open " + name + " -it is not readable", e); | |||
} | |||
readSource(new InputStreamReader(in), name); | |||
try { | |||
readSource(in, name); | |||
} finally { | |||
FileUtils.close(in); | |||
} | |||
} | |||
/** | |||
@@ -356,5 +424,4 @@ public abstract class ScriptRunnerBase { | |||
Thread.currentThread().setContextClassLoader( | |||
origLoader); | |||
} | |||
} |
@@ -31,9 +31,11 @@ import org.apache.tools.ant.types.resources.Union; | |||
public class ScriptRunnerHelper { | |||
private ClasspathUtils.Delegate cpDelegate = null; | |||
private File srcFile; | |||
private String encoding; | |||
private String manager = "auto"; | |||
private String language; | |||
private String text; | |||
private boolean compiled = false; | |||
private boolean setBeans = true; | |||
private ProjectComponent projectComponent; | |||
private ClassLoader scriptLoader = null; | |||
@@ -53,6 +55,12 @@ public class ScriptRunnerHelper { | |||
*/ | |||
public ScriptRunnerBase getScriptRunner() { | |||
ScriptRunnerBase runner = getRunner(); | |||
runner.setCompiled(compiled); | |||
if (encoding != null) { | |||
// set it first, because runner.setSrc() loads immediately the file | |||
runner.setEncoding(encoding); | |||
} | |||
if (srcFile != null) { | |||
runner.setSrc(srcFile); | |||
} | |||
@@ -107,6 +115,16 @@ public class ScriptRunnerHelper { | |||
this.srcFile = file; | |||
} | |||
/** | |||
* Set the encoding of the script from an external file ; optional. | |||
* | |||
* @param encoding the encoding of the file containing the script source. | |||
* @since Ant 1.10.1 | |||
*/ | |||
public void setEncoding(String encoding) { | |||
this.encoding = encoding; | |||
} | |||
/** | |||
* Add script text. | |||
* | |||
@@ -142,6 +160,28 @@ public class ScriptRunnerHelper { | |||
return language; | |||
} | |||
/** | |||
* Enable the compilation of the script if possible. | |||
* If this is true and the compilation feature is available in | |||
* the script engine, the script is compiled before the first | |||
* evaluation, and should be cached for future evaluations. | |||
* Otherwise, a script is evaluated is used. | |||
* The default is false. | |||
* | |||
* @param compiled the value to set. | |||
*/ | |||
public void setCompiled(boolean compiled) { | |||
this.compiled = compiled; | |||
} | |||
/** | |||
* Get the compilation feature. | |||
* @return the compilation feature. | |||
*/ | |||
public boolean getCompiled() { | |||
return this.compiled; | |||
} | |||
/** | |||
* Set the setbeans attribute. | |||
* If this is true, <script> will create variables in the | |||
@@ -21,6 +21,7 @@ package org.apache.tools.ant.util.optional; | |||
import java.util.Iterator; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.util.ReflectWrapper; | |||
import org.apache.tools.ant.util.ScriptRunnerBase; | |||
@@ -31,6 +32,11 @@ import org.apache.tools.ant.util.ScriptRunnerBase; | |||
public class JavaxScriptRunner extends ScriptRunnerBase { | |||
private ReflectWrapper engine; | |||
/** Debug constant */ | |||
private static final boolean DEBUG = Boolean.getBoolean("JavaxScriptRunner.DEBUG"); | |||
private String compiledScriptRefName; | |||
/** | |||
* Get the name of the manager prefix. | |||
* @return "javax" | |||
@@ -79,28 +85,85 @@ public class JavaxScriptRunner extends ScriptRunnerBase { | |||
checkLanguage(); | |||
ClassLoader origLoader = replaceContextLoader(); | |||
try { | |||
if(DEBUG) System.out.println("-- JavaxScriptRunner.evaluateScript : compile enabled [" + getCompiled() + "]"); | |||
if (getCompiled()) { | |||
if (null == compiledScriptRefName) { | |||
compiledScriptRefName = execName + ".compiledScript.0123456789"; | |||
} | |||
ReflectWrapper scriptRefObj = getProject().getReference(compiledScriptRefName); | |||
if (null == scriptRefObj) { | |||
ReflectWrapper engine = createEngine(); | |||
if (engine == null) { | |||
throw new BuildException( | |||
"Unable to create javax script engine for " | |||
+ getLanguage()); | |||
} | |||
final Class engineClass = Class.forName("javax.script.ScriptEngine"); | |||
final Class compilableClass = Class.forName("javax.script.Compilable"); | |||
final Object wrappedObject = engine.getObject(); | |||
if (DEBUG) System.out.println("-- JavaxScriptRunner.evaluateScript : wrappedObject [" + wrappedObject.getClass().getName() + "]"); | |||
if (engineClass.isAssignableFrom(wrappedObject.getClass()) && compilableClass.isAssignableFrom(wrappedObject.getClass())) { | |||
if(DEBUG) System.out.println("-- JavaxScriptRunner.evaluateScript : compilable [" + wrappedObject.getClass().getName() + "]"); | |||
{ | |||
getProject().log("compile script" + compiledScriptRefName, Project.MSG_VERBOSE); | |||
// compilable engine | |||
final Object compiledScript = engine.invoke("compile", String.class, getScript()); | |||
scriptRefObj = new ReflectWrapper(compiledScript); | |||
} | |||
getProject().log("store compiled script, ref " + compiledScriptRefName, Project.MSG_DEBUG); | |||
} else { | |||
getProject().log("script compilation not available", Project.MSG_DEBUG); | |||
scriptRefObj = new ReflectWrapper(null); | |||
} | |||
getProject().addReference(compiledScriptRefName, scriptRefObj); | |||
} | |||
if (null != scriptRefObj.getObject()) { | |||
if (DEBUG) System.out.println("-- JavaxScriptRunner.evaluateScript : execute compiled script"); | |||
final Object simpleBindings; | |||
{ | |||
final Class simpleBindingsClass = Class.forName("javax.script.SimpleBindings"); | |||
simpleBindings = simpleBindingsClass.newInstance(); | |||
} | |||
applyBindings(new ReflectWrapper(simpleBindings)); | |||
if (DEBUG) System.out.println("-- JavaxScriptRunner.evaluateScript : bindings applied"); | |||
getProject().log("run compiled script, ref " + compiledScriptRefName, Project.MSG_DEBUG); | |||
final Class bindingsClass = Class.forName("javax.script.Bindings"); | |||
return scriptRefObj.invoke("eval", bindingsClass, simpleBindings); | |||
} | |||
} | |||
ReflectWrapper engine = createEngine(); | |||
if (engine == null) { | |||
throw new BuildException( | |||
"Unable to create javax script engine for " | |||
+ getLanguage()); | |||
} | |||
for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) { | |||
String key = (String) i.next(); | |||
Object value = getBeans().get(key); | |||
if ("FX".equalsIgnoreCase(getLanguage())) { | |||
engine.invoke( | |||
"put", String.class, key | |||
+ ":" + value.getClass().getName(), | |||
Object.class, value); | |||
} else { | |||
engine.invoke( | |||
"put", String.class, key, | |||
Object.class, value); | |||
} | |||
} | |||
applyBindings(engine); | |||
// execute the script | |||
return engine.invoke("eval", String.class, getScript()); | |||
} catch (BuildException be) { | |||
//catch and rethrow build exceptions | |||
@@ -126,6 +189,23 @@ public class JavaxScriptRunner extends ScriptRunnerBase { | |||
} | |||
} | |||
private void applyBindings(ReflectWrapper engine) { | |||
for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) { | |||
String key = (String) i.next(); | |||
Object value = getBeans().get(key); | |||
if ("FX".equalsIgnoreCase(getLanguage())) { | |||
engine.invoke( | |||
"put", String.class, key | |||
+ ":" + value.getClass().getName(), | |||
Object.class, value); | |||
} else { | |||
engine.invoke( | |||
"put", String.class, key, | |||
Object.class, value); | |||
} | |||
} | |||
} | |||
private ReflectWrapper createEngine() { | |||
if (engine != null) { | |||
return engine; | |||