Browse Source

Scriptdef task new options : 'compiled' (if javax.script engine implements Compilable), 'encoding' to load resources

master
pyxide Stefan Bodewig 8 years ago
parent
commit
4bd9b4a6e4
4 changed files with 230 additions and 27 deletions
  1. +19
    -3
      src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java
  2. +77
    -10
      src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
  3. +40
    -0
      src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java
  4. +94
    -14
      src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java

+ 19
- 3
src/main/org/apache/tools/ant/taskdefs/optional/script/ScriptDef.java View File

@@ -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);
}
}


+ 77
- 10
src/main/org/apache/tools/ant/util/ScriptRunnerBase.java View File

@@ -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);
}

}

+ 40
- 0
src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java View File

@@ -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


+ 94
- 14
src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java View File

@@ -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;


Loading…
Cancel
Save