mirror of
https://github.com/internetarchive/heritrix3.git
synced 2026-09-22 13:46:01 +00:00
revised scripting console xml response fix based on comments.
removed scripting console actions from ScriptModel into ScriptingConsole class (resurrection of ScriptExec). added basic ScriptingConsoleTest.
This commit is contained in:
@@ -92,6 +92,8 @@ public class ScriptResource extends JobRelatedResource {
|
||||
tmpltCfg.setClassForTemplateLoading(this.getClass(),"");
|
||||
tmpltCfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);
|
||||
setTemplateConfiguration(tmpltCfg);
|
||||
|
||||
scriptingConsole = new ScriptingConsole(cj);
|
||||
}
|
||||
public void setTemplateConfiguration(Configuration tmpltCfg) {
|
||||
_templateConfiguration=tmpltCfg;
|
||||
@@ -100,7 +102,7 @@ public class ScriptResource extends JobRelatedResource {
|
||||
return _templateConfiguration;
|
||||
}
|
||||
|
||||
private ScriptModel scriptModel;
|
||||
private ScriptingConsole scriptingConsole;
|
||||
|
||||
@Override
|
||||
public void acceptRepresentation(Representation entity) throws ResourceException {
|
||||
@@ -113,10 +115,9 @@ public class ScriptResource extends JobRelatedResource {
|
||||
|
||||
ScriptEngine eng = MANAGER.getEngineByName(chosenEngine);
|
||||
|
||||
scriptModel = makeDataModel();
|
||||
scriptModel.bind("scriptResource", this);
|
||||
scriptModel.execute(eng, script);
|
||||
scriptModel.unbind("scriptResource");
|
||||
scriptingConsole.bind("scriptResource", this);
|
||||
scriptingConsole.execute(eng, script);
|
||||
scriptingConsole.unbind("scriptResource");
|
||||
|
||||
//TODO: log script, results somewhere; job log INFO?
|
||||
|
||||
@@ -124,14 +125,11 @@ public class ScriptResource extends JobRelatedResource {
|
||||
}
|
||||
|
||||
public Representation represent(Variant variant) throws ResourceException {
|
||||
if (scriptModel == null) {
|
||||
scriptModel = makeDataModel();
|
||||
}
|
||||
Representation representation;
|
||||
if (variant.getMediaType() == MediaType.APPLICATION_XML) {
|
||||
representation = new WriterRepresentation(MediaType.APPLICATION_XML) {
|
||||
public void write(Writer writer) throws IOException {
|
||||
XmlMarshaller.marshalDocument(writer,"script", scriptModel);
|
||||
XmlMarshaller.marshalDocument(writer,"script", makeDataModel());
|
||||
}
|
||||
};
|
||||
} else {
|
||||
@@ -172,7 +170,7 @@ public class ScriptResource extends JobRelatedResource {
|
||||
}
|
||||
Reference baseRefRef = new Reference(baseRef);
|
||||
|
||||
ScriptModel model = new ScriptModel(cj,
|
||||
ScriptModel model = new ScriptModel(scriptingConsole,
|
||||
new Reference(baseRefRef, "..").getTargetRef().toString(),
|
||||
getAvailableScriptEngines());
|
||||
|
||||
@@ -193,7 +191,7 @@ public class ScriptResource extends JobRelatedResource {
|
||||
viewModel.put("cssRef", getStylesheetRef());
|
||||
viewModel.put("staticRef", getStaticRef(""));
|
||||
viewModel.put("baseResourceRef",getRequest().getRootRef().toString()+"/engine/static/");
|
||||
viewModel.put("model", scriptModel);
|
||||
viewModel.put("model", makeDataModel());
|
||||
viewModel.put("selectedEngine", chosenEngine);
|
||||
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.archive.crawler.restlet;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.archive.crawler.framework.BeanLookupBindings;
|
||||
import org.archive.crawler.framework.CrawlJob;
|
||||
|
||||
/**
|
||||
* ScriptingConsole implements view-independent logic of scripting console.
|
||||
*
|
||||
* Currently it is short-lived; it is created by ScriptResource for each request and
|
||||
* destroyed after rendering the view.
|
||||
*
|
||||
* @contributor kenji
|
||||
*
|
||||
*/
|
||||
public class ScriptingConsole {
|
||||
private final CrawlJob cj;
|
||||
|
||||
private ScriptEngine eng;
|
||||
private String script;
|
||||
private Bindings bindings;
|
||||
|
||||
private StringWriter rawString;
|
||||
private StringWriter htmlString;
|
||||
private Throwable exception;
|
||||
private int linesExecuted;
|
||||
|
||||
private List<Map<String, String>> availableGlobalVariables;
|
||||
|
||||
public ScriptingConsole(CrawlJob job) {
|
||||
this.cj = job;
|
||||
this.bindings = new BeanLookupBindings(this.cj.getJobContext());
|
||||
this.script = "";
|
||||
|
||||
setupAvailableGlobalVariables();
|
||||
}
|
||||
protected void addGlobalVariable(String name, String desc) {
|
||||
Map<String, String> var = new LinkedHashMap<String, String>();
|
||||
var.put("variable", name);
|
||||
var.put("description", desc);
|
||||
availableGlobalVariables.add(var);
|
||||
}
|
||||
private void setupAvailableGlobalVariables() {
|
||||
availableGlobalVariables = new LinkedList<Map<String,String>>();
|
||||
addGlobalVariable("rawOut", "a PrintWriter for arbitrary text output to this page");
|
||||
addGlobalVariable("htmlOut", "a PrintWriter for HTML output to this page");
|
||||
addGlobalVariable("job", "the current CrawlJob instance");
|
||||
addGlobalVariable("appCtx", "current job ApplicationContext, if any");
|
||||
// TODO: a bit awkward to have this here, because ScriptingConsole has no ref to
|
||||
// ScriptResource. better to have ScriptResource call #addGlobalVariable(String, String)?
|
||||
addGlobalVariable("scriptResource",
|
||||
"the ScriptResource implementing this page, which offers utility methods");
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj) {
|
||||
bindings.put(name, obj);
|
||||
}
|
||||
public Object unbind(String name) {
|
||||
return bindings.remove(name);
|
||||
}
|
||||
public void execute(ScriptEngine eng, String script) {
|
||||
// TODO: update through setter rather than passing as method arguments?
|
||||
this.eng = eng;
|
||||
this.script = script;
|
||||
|
||||
bind("job", cj);
|
||||
rawString = new StringWriter();
|
||||
htmlString = new StringWriter();
|
||||
PrintWriter rawOut = new PrintWriter(rawString);
|
||||
PrintWriter htmlOut = new PrintWriter(htmlString);
|
||||
bind("rawOut", rawOut);
|
||||
bind("htmlOut", htmlOut);
|
||||
bind("appCtx", cj.getJobContext());
|
||||
exception = null;
|
||||
try {
|
||||
this.eng.eval(this.script, bindings);
|
||||
// TODO: should count with RE rather than creating String[]?
|
||||
linesExecuted = script.split("\r?\n").length;
|
||||
} catch (ScriptException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
exception = cause != null ? cause : ex;
|
||||
} catch (RuntimeException ex) {
|
||||
exception = ex;
|
||||
} finally {
|
||||
rawOut.flush();
|
||||
htmlOut.flush();
|
||||
// TODO: are these really necessary?
|
||||
unbind("rawOut");
|
||||
unbind("htmlOut");
|
||||
unbind("appCtx");
|
||||
unbind("job");
|
||||
}
|
||||
}
|
||||
public CrawlJob getCrawlJob( ) {
|
||||
return cj;
|
||||
}
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
public int getLinesExecuted() {
|
||||
return linesExecuted;
|
||||
}
|
||||
public String getRawOutput() {
|
||||
return rawString != null ? rawString.toString() : "";
|
||||
}
|
||||
public String getHtmlOutput() {
|
||||
return htmlString != null ? htmlString.toString() : "";
|
||||
}
|
||||
public String getScript() {
|
||||
return script;
|
||||
}
|
||||
|
||||
public List<Map<String, String>> getAvailableGlobalVariables() {
|
||||
return availableGlobalVariables;
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,13 @@ package org.archive.crawler.restlet.models;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
import org.archive.crawler.framework.BeanLookupBindings;
|
||||
import org.archive.crawler.framework.CrawlJob;
|
||||
import org.archive.crawler.restlet.ScriptingConsole;
|
||||
|
||||
@XmlRootElement(name="script")
|
||||
@XmlType(propOrder={
|
||||
@@ -24,134 +18,52 @@ import org.archive.crawler.framework.CrawlJob;
|
||||
"availableGlobalVariables"
|
||||
})
|
||||
public class ScriptModel {
|
||||
private CrawlJob cj;
|
||||
private String crawlJobUrl;
|
||||
private Collection<Map<String, String>> availableScriptEngines;
|
||||
|
||||
//private ApplicationContext appCtx;
|
||||
private ScriptEngine eng;
|
||||
private String script;
|
||||
private Bindings bindings;
|
||||
|
||||
private StringWriter rawString;
|
||||
private StringWriter htmlString;
|
||||
private Throwable exception;
|
||||
private int linesExecuted;
|
||||
|
||||
private List<Map<String, String>> availableGlobalVariables;
|
||||
private ScriptingConsole scriptingConsole;
|
||||
|
||||
public ScriptModel(CrawlJob cj,
|
||||
public ScriptModel(ScriptingConsole cc,
|
||||
String crawlJobUrl,
|
||||
Collection<Map<String, String>> scriptEngines) {
|
||||
scriptingConsole = cc;
|
||||
this.crawlJobUrl = crawlJobUrl;
|
||||
this.cj = cj;
|
||||
this.availableScriptEngines = scriptEngines;
|
||||
|
||||
List<Map<String,String>> vars = new LinkedList<Map<String,String>>();
|
||||
Map<String,String> var;
|
||||
|
||||
var = new LinkedHashMap<String,String>();
|
||||
var.put("variable", "rawOut");
|
||||
var.put("description", "a PrintWriter for arbitrary text output to this page");
|
||||
vars.add(var);
|
||||
|
||||
var = new LinkedHashMap<String,String>();
|
||||
var.put("variable", "htmlOut");
|
||||
var.put("description", "a PrintWriter for HTML output to this page");
|
||||
vars.add(var);
|
||||
|
||||
var = new LinkedHashMap<String,String>();
|
||||
var.put("variable", "job");
|
||||
var.put("description", "the current CrawlJob instance");
|
||||
vars.add(var);
|
||||
|
||||
var = new LinkedHashMap<String,String>();
|
||||
var.put("variable", "appCtx");
|
||||
var.put("description", "current job ApplicationContext, if any");
|
||||
vars.add(var);
|
||||
|
||||
var = new LinkedHashMap<String,String>();
|
||||
var.put("variable", "scriptResource");
|
||||
var.put("description", "the ScriptResource implementing this page, which offers utility methods");
|
||||
vars.add(var);
|
||||
|
||||
this.availableGlobalVariables = vars;
|
||||
|
||||
this.bindings = new BeanLookupBindings(this.cj.getJobContext());
|
||||
this.script = "";
|
||||
}
|
||||
|
||||
public void bind(String name, Object obj) {
|
||||
bindings.put(name, obj);
|
||||
}
|
||||
public Object unbind(String name) {
|
||||
return bindings.remove(name);
|
||||
}
|
||||
public void execute(ScriptEngine eng, String script) {
|
||||
// TODO: update through setter rather than passing as method arguments?
|
||||
this.eng = eng;
|
||||
this.script = script;
|
||||
|
||||
bind("job", cj);
|
||||
rawString = new StringWriter();
|
||||
htmlString = new StringWriter();
|
||||
PrintWriter rawOut = new PrintWriter(rawString);
|
||||
PrintWriter htmlOut = new PrintWriter(htmlString);
|
||||
bind("rawOut", rawOut);
|
||||
bind("htmlOut", htmlOut);
|
||||
bind("appCtx", cj.getJobContext());
|
||||
try {
|
||||
this.eng.eval(this.script, bindings);
|
||||
// TODO: should count with RE rather than creating String[]?
|
||||
linesExecuted = script.split("\r?\n").length;
|
||||
} catch (ScriptException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
exception = cause != null ? cause : ex;
|
||||
} catch (RuntimeException ex) {
|
||||
exception = ex;
|
||||
} finally {
|
||||
rawOut.flush();
|
||||
htmlOut.flush();
|
||||
// TODO: are these really necessary?
|
||||
unbind("rawOut");
|
||||
unbind("htmlOut");
|
||||
unbind("appCtx");
|
||||
unbind("job");
|
||||
}
|
||||
}
|
||||
public boolean isFailure() {
|
||||
return exception != null;
|
||||
return scriptingConsole.getException() != null;
|
||||
}
|
||||
public String getStackTrace() {
|
||||
Throwable exception = scriptingConsole.getException();
|
||||
if (exception == null) return "";
|
||||
StringWriter s = new StringWriter();
|
||||
exception.printStackTrace(new PrintWriter(s));
|
||||
return s.toString();
|
||||
}
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
return scriptingConsole.getException();
|
||||
}
|
||||
public int getLinesExecuted() {
|
||||
return linesExecuted;
|
||||
return scriptingConsole.getLinesExecuted();
|
||||
}
|
||||
public String getRawOutput() {
|
||||
return rawString != null ? rawString.toString() : "";
|
||||
return scriptingConsole.getRawOutput();
|
||||
}
|
||||
public String getHtmlOutput() {
|
||||
return htmlString != null ? htmlString.toString() : "";
|
||||
return scriptingConsole.getHtmlOutput();
|
||||
}
|
||||
public String getScript() {
|
||||
return script;
|
||||
return scriptingConsole.getScript();
|
||||
}
|
||||
|
||||
public String getCrawlJobShortName() {
|
||||
return cj.getShortName();
|
||||
return scriptingConsole.getCrawlJob().getShortName();
|
||||
}
|
||||
public Collection<Map<String, String>> getAvailableScriptEngines() {
|
||||
return availableScriptEngines;
|
||||
}
|
||||
public List<Map<String, String>> getAvailableGlobalVariables() {
|
||||
return availableGlobalVariables;
|
||||
return scriptingConsole.getAvailableGlobalVariables();
|
||||
}
|
||||
public String getCrawlJobUrl() {
|
||||
return crawlJobUrl;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.archive.crawler.restlet;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.archive.crawler.framework.CrawlJob;
|
||||
import org.archive.spring.PathSharingContext;
|
||||
|
||||
public class ScriptingConsoleTest extends TestCase {
|
||||
// barebone CrawlJob object.
|
||||
public static class TestCrawlJob extends CrawlJob {
|
||||
public TestCrawlJob() {
|
||||
super(null);
|
||||
this.ac = new PathSharingContext(new String[0]);
|
||||
}
|
||||
@Override
|
||||
protected void scanJobLog() {
|
||||
}
|
||||
}
|
||||
CrawlJob cj;
|
||||
ScriptingConsole sc;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
cj = new TestCrawlJob();
|
||||
sc = new ScriptingConsole(cj);
|
||||
}
|
||||
|
||||
public void testInitialState() {
|
||||
assertEquals("script is empty", "", sc.getScript());
|
||||
assertNull("exception is null", sc.getException());
|
||||
}
|
||||
|
||||
public void testExecute() {
|
||||
final String script = "rawOut.println 'elk'";
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine eng = manager.getEngineByName("groovy");
|
||||
sc.execute(eng, script);
|
||||
|
||||
assertNull("exception is null", sc.getException());
|
||||
assertEquals("has the same script", sc.getScript(), script);
|
||||
assertEquals("linesExecuted", 1, sc.getLinesExecuted());
|
||||
assertEquals("rawOut", "elk\n", sc.getRawOutput());
|
||||
|
||||
}
|
||||
|
||||
public void testExecuteError() {
|
||||
final String script = "rawOut.println undef";
|
||||
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||
final ScriptEngine eng = manager.getEngineByName("groovy");
|
||||
sc.execute(eng, script);
|
||||
|
||||
assertNotNull("exception is non-null", sc.getException());
|
||||
assertEquals("rawOut", "", sc.getRawOutput());
|
||||
assertEquals("linesExecuted", 0, sc.getLinesExecuted());
|
||||
|
||||
// extra test - it is okay to fail this test is okay because
|
||||
// ScriptingConsole is single-use now.
|
||||
sc.execute(eng, "rawOut.println 1");
|
||||
assertNull("exception is cleared", sc.getException());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user