diff --git a/engine/src/main/java/org/archive/crawler/framework/ActionDirectory.java b/engine/src/main/java/org/archive/crawler/framework/ActionDirectory.java index 305137c2..3b86df56 100644 --- a/engine/src/main/java/org/archive/crawler/framework/ActionDirectory.java +++ b/engine/src/main/java/org/archive/crawler/framework/ActionDirectory.java @@ -31,6 +31,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; @@ -311,22 +312,20 @@ public class ActionDirectory implements ApplicationContextAware, Lifecycle, Runn StringWriter rawString = new StringWriter(); PrintWriter rawOut = new PrintWriter(rawString); Exception ex = null; - engine.put("rawOut", rawOut); - engine.put("appCtx", appCtx); + Bindings bindings = new BeanLookupBindings(appCtx); + bindings.put("rawOut", rawOut); + bindings.put("appCtx", appCtx); // evaluate and record any exception try { String script = FileUtils.readFileToString(actionFile); - engine.eval(script); + engine.eval(script, bindings); } catch (IOException e) { ex = e; } catch (ScriptException e) { ex = e; } catch (RuntimeException e) { ex = e; - } finally { - engine.put("rawOut", null); - engine.put("appCtx", null); } // report output/exception to files paired with script in done dir diff --git a/engine/src/main/java/org/archive/crawler/framework/BeanLookupBindings.java b/engine/src/main/java/org/archive/crawler/framework/BeanLookupBindings.java new file mode 100644 index 00000000..ca74c462 --- /dev/null +++ b/engine/src/main/java/org/archive/crawler/framework/BeanLookupBindings.java @@ -0,0 +1,66 @@ +package org.archive.crawler.framework; + +import java.util.Map; + +import javax.script.SimpleBindings; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; + +/** + * Provides syntactic sugar for H3 scripts to reference beans without adding a + * line like {@code def scope = appCtx.getBean("scope");}. Instead, the script + * may simply reference {@code scope}. Caveat: access is read only. + * + * @contributor travis + */ +public class BeanLookupBindings extends SimpleBindings { + + private ApplicationContext appCtx = null; + + public BeanLookupBindings(ApplicationContext appCtx) { + assert appCtx != null; + this.appCtx = appCtx; + } + + public BeanLookupBindings(ApplicationContext appCtx, Map m) { + super(m); + assert appCtx != null; + this.appCtx = appCtx; + } + + @Override + public Object get(Object key) { + if (key instanceof String) { + try { + Object ret = appCtx.getBean((String) key); + if (ret != null) { + return ret; + } + } catch (BeansException e) {} + } + return super.get(key); + } + + @Override + public boolean containsKey(Object key) { + if (key instanceof String) { + try { + boolean ret = appCtx.containsBean((String) key); + if (ret == true) { + return ret; + } + } catch (BeansException e) {} + } + return super.containsKey(key); + } + + @Override + public Object put(String name, Object value) { + // restrict setting variables that conflict with bean names + if (appCtx.containsBean(name)) { + throw new IllegalArgumentException("name conflict: \""+ name +"\" is the name of a bean."); + } + return super.put(name, value); + } +} diff --git a/engine/src/main/java/org/archive/crawler/restlet/ScriptResource.java b/engine/src/main/java/org/archive/crawler/restlet/ScriptResource.java index ab8247c6..52382529 100644 --- a/engine/src/main/java/org/archive/crawler/restlet/ScriptResource.java +++ b/engine/src/main/java/org/archive/crawler/restlet/ScriptResource.java @@ -31,6 +31,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; @@ -38,6 +39,7 @@ import javax.script.ScriptException; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; +import org.archive.crawler.framework.BeanLookupBindings; import org.archive.util.TextUtils; import org.restlet.Context; import org.restlet.data.CharacterSet; @@ -50,6 +52,7 @@ import org.restlet.resource.Representation; import org.restlet.resource.ResourceException; import org.restlet.resource.Variant; import org.restlet.resource.WriterRepresentation; +import org.springframework.context.ApplicationContext; /** * Restlet Resource which runs an arbitrary script, which is supplied @@ -102,13 +105,15 @@ public class ScriptResource extends JobRelatedResource { StringWriter rawString = new StringWriter(); PrintWriter rawOut = new PrintWriter(rawString); + ApplicationContext appCtx = cj.getJobContext(); + Bindings bindings = new BeanLookupBindings(appCtx); eng.put("rawOut", rawOut); StringWriter htmlString = new StringWriter(); PrintWriter htmlOut = new PrintWriter(htmlString); - eng.put("htmlOut", htmlOut); - eng.put("job", cj); - eng.put("appCtx", cj.getJobContext()); - eng.put("scriptResource", this); + bindings.put("htmlOut", htmlOut); + bindings.put("job", cj); + bindings.put("appCtx", appCtx); + bindings.put("scriptResource", this); try { eng.eval(script); linesExecuted = script.split("\r?\n").length; @@ -121,12 +126,6 @@ public class ScriptResource extends JobRelatedResource { rawOutput = rawString.toString(); htmlOut.flush(); htmlOutput = htmlString.toString(); - - eng.put("rawOut", null); - eng.put("htmlOut", null); - eng.put("job", null); - eng.put("appCtx", null); - eng.put("scriptResource", null); } //TODO: log script, results somewhere; job log INFO?