BeanLookupBindings for simpler script access to beans

The new class BeanLookupBindings allows scripts to skip getBean calls.
Lines like 'beanname = appCtx.getBean("beanname")' can be left out.
Past scripts remain compatible.
This change effects action directory scripts and rest console scripts.
This commit is contained in:
Travis Wellman
2013-01-10 18:54:33 -08:00
parent d27f67897e
commit 03914a246c
3 changed files with 80 additions and 16 deletions
@@ -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
@@ -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<String, Object> 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);
}
}
@@ -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?