/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.monkeytalk.processor.js;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import com.gorillalogic.monkeytalk.processor.ScriptProcessor;
import com.gorillalogic.monkeytalk.utils.FileUtils;
/**
* Use the embedded scripting engine capabilities in Java 6 to run Javascript scripts.
* Unfortunately, the embedded engine doesn't have all the Rhino Shell stuff, so we must add our own
* custom {@link MonkeyTalkJS#load(String)} impl at the top level of the Javascript execution scope.
*/
public class MonkeyTalkJS {
private final ScriptEngine engine;
private final ScriptProcessor processor;
private final File rootDir;
/**
* Instantiate a new {@code ScriptEngine} for running Javascript scripts with the given script
* processor. Since the embedded scripting engine doesn't have all the Rhino Shell stuff, we
* must add our own custom {@link MonkeyTalkJS#load(String)} impl at the top level scope. We
* also add the {@link ScriptProcessor} at the top level scope.
*
* @param processor
* the script processor
* @throws ScriptException
*/
public MonkeyTalkJS(ScriptProcessor processor) throws ScriptException {
this.processor = processor;
this.rootDir = processor.getWorld().getRootDir();
ScriptEngineManager factory = new ScriptEngineManager();
engine = factory.getEngineByName("JavaScript");
engine.put("MonkeyTalkJS", this);
engine.put("ProcessorObj", processor);
engine.put(ScriptEngine.FILENAME, "MonkeyTalkJS.js");
engine.eval("function load(filename) { MonkeyTalkJS.load(filename); }");
engine.eval("function print(msg) { MonkeyTalkJS.print(msg); }");
}
/**
* Our custom {@code load()} impl that is injected into the top level scope of the Javascript
* engine.
*
* @param filename
* the path of the Javascript file to load and {@code eval()}.
* @throws ScriptException
*/
public void load(String filename) throws ScriptException {
File f = new File(rootDir, filename);
try {
String js = FileUtils.readFile(f);
engine.put(ScriptEngine.FILENAME, filename);
engine.eval(js);
} catch (FileNotFoundException ex) {
throw new RuntimeException("file not found: " + f.getAbsolutePath() + "\n\t" + ex);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("bad encoding: " + f.getAbsolutePath() + "\n\t" + ex);
} catch (IOException ex) {
throw new RuntimeException("file load error: " + f.getAbsolutePath() + "\n\t" + ex);
} catch (ScriptException ex) {
throw new RuntimeException("script error: " + f.getAbsolutePath() + "\n\t" + ex);
}
}
/**
* Our custom {@code print()} impl that is injected into the top-level scope of the Javascript
* engine.
*
* @param msg
* the message to print
*/
public void print(String msg) {
processor.getPlaybackListener().onPrint(msg);
}
/**
* Get the Javascript script engine.
*
* @return the script engine
*/
public ScriptEngine getEngine() {
return engine;
}
/**
* Get the filename of the current script.
*
* @return the script filename
*/
public String getFilename() {
return engine.get(ScriptEngine.FILENAME).toString();
}
}