mirror of
https://github.com/internetarchive/heritrix3.git
synced 2026-07-18 13:37:20 +00:00
scripting console:
fix bug: exception from script execution is not displayed. remove extra space around exception and rawOutput. involves a bit more than bug fix. introduced ScriptExecution class for encapsulating script, execution, and result.
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
|
||||
package org.archive.crawler.restlet;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
@@ -38,14 +37,10 @@ import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
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.crawler.restlet.models.CrawlJobModel;
|
||||
import org.archive.crawler.restlet.models.EngineModel;
|
||||
import org.archive.crawler.restlet.models.ScriptModel;
|
||||
import org.archive.crawler.restlet.models.ViewModel;
|
||||
import org.archive.util.TextUtils;
|
||||
import org.restlet.Context;
|
||||
import org.restlet.data.CharacterSet;
|
||||
import org.restlet.data.Form;
|
||||
@@ -89,11 +84,13 @@ public class ScriptResource extends JobRelatedResource {
|
||||
}
|
||||
});
|
||||
}
|
||||
protected String script = "";
|
||||
protected Exception ex = null;
|
||||
protected int linesExecuted = 0;
|
||||
protected String rawOutput = "";
|
||||
protected String htmlOutput = "";
|
||||
//protected String script = "";
|
||||
//protected Exception ex = null;
|
||||
//protected int linesExecuted = 0;
|
||||
//protected String rawOutput = "";
|
||||
//protected String htmlOutput = "";
|
||||
ScriptExecution scriptExec = null;
|
||||
|
||||
protected String chosenEngine = FACTORIES.isEmpty() ? "" : FACTORIES.getFirst().getNames().get(0);
|
||||
private Configuration _templateConfiguration;
|
||||
|
||||
@@ -115,48 +112,107 @@ public class ScriptResource extends JobRelatedResource {
|
||||
return _templateConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaBean that packages script, its execution and the result.
|
||||
*
|
||||
* TODO: the script could create an object that persists and retains a
|
||||
* reference to the Bindings. by encapsulating this way, I've made it
|
||||
* a bit more difficult? we could {@code eng} and {@code script} arguments
|
||||
* to execute() method.
|
||||
*/
|
||||
public static class ScriptExecution {
|
||||
private ScriptEngine eng;
|
||||
private ApplicationContext appCtx;
|
||||
private Bindings bindings;
|
||||
private String script;
|
||||
|
||||
private StringWriter rawString;
|
||||
private StringWriter htmlString;
|
||||
private Throwable exception;
|
||||
private int linesExecuted;
|
||||
|
||||
public ScriptExecution(ScriptEngine eng, ApplicationContext appCtx, String script) {
|
||||
this.eng = eng;
|
||||
this.appCtx = appCtx;
|
||||
this.bindings = new BeanLookupBindings(appCtx);
|
||||
this.script = script;
|
||||
if (StringUtils.isBlank(this.script)) {
|
||||
this.script = "";
|
||||
}
|
||||
this.rawString = new StringWriter();
|
||||
this.htmlString = new StringWriter();
|
||||
}
|
||||
public void bind(String name, Object obj) {
|
||||
bindings.put(name, obj);
|
||||
}
|
||||
public Object unbind(String name) {
|
||||
return bindings.remove(name);
|
||||
}
|
||||
public void execute() {
|
||||
PrintWriter rawOut = new PrintWriter(rawString);
|
||||
PrintWriter htmlOut = new PrintWriter(htmlString);
|
||||
bind("rawOut", rawOut);
|
||||
bind("htmlOut", htmlOut);
|
||||
bind("appCtx", appCtx);
|
||||
try {
|
||||
eng.eval(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");
|
||||
}
|
||||
}
|
||||
public boolean isFailure() {
|
||||
return exception != null;
|
||||
}
|
||||
public String getStackTrace() {
|
||||
if (exception == null) return "";
|
||||
StringWriter s = new StringWriter();
|
||||
exception.printStackTrace(new PrintWriter(s));
|
||||
return s.toString();
|
||||
}
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
public int getLinesExecuted() {
|
||||
return linesExecuted;
|
||||
}
|
||||
public String getRawOutput() {
|
||||
return rawString.toString();
|
||||
}
|
||||
public String getHtmlOutput() {
|
||||
return htmlString.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptRepresentation(Representation entity) throws ResourceException {
|
||||
Form form = getRequest().getEntityAsForm();
|
||||
chosenEngine = form.getFirstValue("engine");
|
||||
script = form.getFirstValue("script");
|
||||
String script = form.getFirstValue("script");
|
||||
if(StringUtils.isBlank(script)) {
|
||||
script="";
|
||||
}
|
||||
|
||||
ScriptEngine eng = MANAGER.getEngineByName(chosenEngine);
|
||||
|
||||
StringWriter rawString = new StringWriter();
|
||||
PrintWriter rawOut = new PrintWriter(rawString);
|
||||
ApplicationContext appCtx = cj.getJobContext();
|
||||
Bindings bindings = new BeanLookupBindings(appCtx);
|
||||
bindings.put("rawOut", rawOut);
|
||||
StringWriter htmlString = new StringWriter();
|
||||
PrintWriter htmlOut = new PrintWriter(htmlString);
|
||||
bindings.put("htmlOut", htmlOut);
|
||||
bindings.put("job", cj);
|
||||
bindings.put("appCtx", appCtx);
|
||||
bindings.put("scriptResource", this);
|
||||
try {
|
||||
eng.eval(script, bindings);
|
||||
linesExecuted = script.split("\r?\n").length;
|
||||
} catch (ScriptException e) {
|
||||
ex = e;
|
||||
} catch (RuntimeException e) {
|
||||
ex = e;
|
||||
} finally {
|
||||
rawOut.flush();
|
||||
rawOutput = rawString.toString();
|
||||
htmlOut.flush();
|
||||
htmlOutput = htmlString.toString();
|
||||
|
||||
// the script could create an object that persists and retains a reference to the Bindings
|
||||
bindings.put("rawOut", null);
|
||||
bindings.put("htmlOut", null);
|
||||
bindings.put("job", null);
|
||||
bindings.put("appCtx", null);
|
||||
bindings.put("scriptResource", null);
|
||||
}
|
||||
scriptExec = new ScriptExecution(eng, cj.getJobContext(), script);
|
||||
scriptExec.bind("job", cj);
|
||||
scriptExec.bind("scriptResource", this);
|
||||
scriptExec.execute();
|
||||
scriptExec.unbind("job");
|
||||
scriptExec.unbind("scriptResource");
|
||||
|
||||
//TODO: log script, results somewhere; job log INFO?
|
||||
|
||||
getResponse().setEntity(represent());
|
||||
@@ -211,10 +267,7 @@ public class ScriptResource extends JobRelatedResource {
|
||||
ScriptModel model = new ScriptModel(cj.getShortName(),
|
||||
new Reference(baseRefRef, "..").getTargetRef().toString(),
|
||||
getAvailableScriptEngines(),
|
||||
linesExecuted,
|
||||
ex,
|
||||
rawOutput,
|
||||
htmlOutput);
|
||||
scriptExec);
|
||||
|
||||
return model;
|
||||
}
|
||||
@@ -235,7 +288,6 @@ public class ScriptResource extends JobRelatedResource {
|
||||
viewModel.put("baseResourceRef",getRequest().getRootRef().toString()+"/engine/static/");
|
||||
viewModel.put("model",makeDataModel());
|
||||
viewModel.put("selectedEngine", chosenEngine);
|
||||
viewModel.put("script", script);
|
||||
|
||||
try {
|
||||
Template template = tmpltCfg.getTemplate("Script.ftl");
|
||||
|
||||
@@ -6,29 +6,23 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.archive.crawler.restlet.ScriptResource.ScriptExecution;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class ScriptModel extends LinkedHashMap<String, Object> {
|
||||
|
||||
public ScriptModel(String crawlJobShortName, String crawlJobUrl, Collection<Map<String,String>> scriptEngines, int linesExecuted, Exception exception, String rawOutput, String htmlOutput){
|
||||
public ScriptModel(String crawlJobShortName, String crawlJobUrl,
|
||||
Collection<Map<String, String>> scriptEngines,
|
||||
ScriptExecution scriptExec) {// int linesExecuted, Exception
|
||||
// exception, String rawOutput,
|
||||
// String htmlOutput){
|
||||
super();
|
||||
this.put("crawlJobUrl",crawlJobUrl);
|
||||
this.put("crawlJobShortName", crawlJobShortName);
|
||||
this.put("availableScriptEngines", scriptEngines);
|
||||
|
||||
if (linesExecuted > 0) {
|
||||
this.put("linesExecuted", linesExecuted);
|
||||
}
|
||||
if (exception != null) {
|
||||
this.put("exception", exception);
|
||||
}
|
||||
if (StringUtils.isNotBlank(rawOutput)) {
|
||||
this.put("rawOutput", rawOutput);
|
||||
}
|
||||
if (StringUtils.isNotBlank(htmlOutput)) {
|
||||
this.put("htmlOutput", htmlOutput);
|
||||
}
|
||||
if (scriptExec != null)
|
||||
this.put("scriptExec", scriptExec);
|
||||
|
||||
List<Map<String,String>> vars = new LinkedList<Map<String,String>>();
|
||||
Map<String,String> var;
|
||||
|
||||
@@ -16,35 +16,37 @@
|
||||
<body>
|
||||
<h1>Execute script for job <i><a href='/engine/job/${model.crawlJobShortName}'>${model.crawlJobShortName}</a></i></h1>
|
||||
|
||||
<#if model.linesExecuted??>
|
||||
<span class='success'>${model.linesExecuted} lines executed<span>
|
||||
<#if model.scriptExec??>
|
||||
<#if (model.scriptExec.linesExecuted > 0)>
|
||||
<span class='success'>${model.scriptExec.linesExecuted} lines executed<span>
|
||||
</#if>
|
||||
<#if model.ex??>
|
||||
<pre style='color:red; height:150px; overflow:auto'>
|
||||
${model.ex.printStackTrace()}
|
||||
<#if model.scriptExec.failure>
|
||||
<pre style='color:red; height:150px; overflow:auto'>${model.scriptExec.stackTrace}
|
||||
</pre>
|
||||
</#if>
|
||||
<#if model.htmlOutput??>
|
||||
<#assign htmlOutput=model.scriptExec.htmlOutput>
|
||||
<#if (htmlOutput?length > 0)>
|
||||
<fieldset><legend>htmlOut</legend>
|
||||
${model.htmlOutput}
|
||||
${htmlOutput}
|
||||
</fieldset>
|
||||
</#if>
|
||||
<#if model.rawOutput??>
|
||||
<#assign rawOutput=model.scriptExec.rawOutput>
|
||||
<#if (rawOutput?length > 0)>
|
||||
<fieldset><legend>rawOutput</legend>
|
||||
<pre>
|
||||
${model.rawOutput?html}
|
||||
<pre style="margin:0;">${rawOutput}
|
||||
</pre>
|
||||
</fieldset>
|
||||
</#if>
|
||||
</#if>
|
||||
|
||||
<form method="POST">
|
||||
<input type="submit" value="execute">
|
||||
<select name="engine" id="selectEngine">
|
||||
<#list model.availableScriptEngines as scriptEngine>
|
||||
<option<#if selectedEngine=scriptEngine.engine> selected='selected'</#if> value='${scriptEngine.engine}'>${scriptEngine.language}</option>
|
||||
<option<#if selectedEngine=scriptEngine.engine> selected="selected"</#if> value="${scriptEngine.engine}">${scriptEngine.language}</option>
|
||||
</#list>
|
||||
</select>
|
||||
<textarea rows='20' style='width:100%' name='script' id='editor'>${script}</textarea>
|
||||
<textarea rows='20' style='width:100%' name='script' id='editor'>${(model.scriptExec.script)!""}</textarea>
|
||||
<input type='submit' value='execute'></input>
|
||||
</form>
|
||||
The script will be executed in an engine preloaded
|
||||
|
||||
Reference in New Issue
Block a user