"clone" already loaded Scripts without rerunning them in java ScriptEngine - javascript

So, my problem is the following:
Lets say, i have a base of js modules which need to be preloaded.
I have now several scripts which need to be able to be run without interfereing into others.
The scripts look like this:
function A(){
}
function B(){
}
What i want to do is call Function A from Script 1 and Function A from Script 2. But only the last Script is executed correctly since it is the same ScriptEngine I am calling.
I tried an attempt like this:
public static ScriptEngine eval(BufferedReader file) throws ScriptException {
SimpleScriptContext context = new SimpleScriptContext();
context.getBindings(ScriptContext.ENGINE_SCOPE).putAll(engine.getBindings(ScriptContext.ENGINE_SCOPE));
ScriptEngine dengine = new NashornScriptEngineFactory().getScriptEngine("-strict");
dengine.eval(file,context);
ClassLoader cl = MyClass.getInstance().getClass().getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
return dengine;
}
to create multiple ScriptEngines. But that failed. So what is the right attempt, to "clone" already loaded Scripts without rerunning them?

Related

How do I check if a specific module has been added to a Worklet?

I’m working with AudioWorkletNode and, to use it, it requires you to first load a processor module on the audio_context.audioWorklet.
DOMException: Failed to construct 'AudioWorkletNode': AudioWorkletNode cannot be created: AudioWorklet does not have a valid AudioWorkletGlobalScope. Load a script via audioWorklet.addModule() first.
Due to the modular nature of my code, I need a reliable way to prevent the unnecessary multiple loading of the processor module; not to .addModule if already done to a given AudioContext. Is there such a way other than try-catching and marking on the AudioContext object?
Let's say you have named your processor my-processor and the definition of your AudioWorkletProcessor looks somehow like this:
class MyProcessor extends AudioWorkletProcessor {
process () {
return true;
}
}
registerProcessor('my-processor', MyProcessor);
To check if that processor is already loaded you can do something like this from within the main thread:
// somewhere inside of an async function ...
let audioWorkletNode;
try {
audioWorkletNode = new AudioWorkletNode(audioContext, 'my-processor');
} catch (err) {
await audioContext.audioWorklet.addModule('./worklet.js');
audioWorkletNode = new AudioWorkletNode(audioContext, 'my-processor');
}
The code is using a try/catch block but it does at least not load the JS file if it was already loaded before.

Is it possible to import javascript files to a java ScriptEngine

I am using nashorn java ScriptEngine. I would like to evaluate a script which includes other scripts. I know I can use the load directive directly in the javascript itself, but I would prefer to import or load it directly from the java code instanciating the scriptEngine.
Is there a way to do this ? Something like :
void evaluateScript(String scriptName, String dependency) {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine jsEngine = factory.getEngineByName("nashorn");
jsEngine.load(depency); // does not exist.
jsEngine.eval();
}
I see the "load" function does not exist. How could I achieve this?
Thanks
Actually I found the answer myself: as mentioned in the comment, it is possible to call several eval with different scripts, same engine, and the engine will keep the evaluated scripts in its context. So here is my code:
public void executeScript(String scriptName, String[] dependencies) {
try {
FileReader script = new FileReader(scriptName);
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine jsEngine = factory.getEngineByName("nashorn");
if(dependencies != null) {
for (String dependency : dependencies) {
FileReader dependencyFile = new FileReader(dependency);
jsEngine.eval(dependencyFile);
}
}
jsEngine.eval(script);
}
}
I can define functions in my dependencies and use them in the script of name scriptName.
javax.script.ScriptEngine has many "eval" methods - there are java.io.Reader accepting eval methods like this -> eval
You can pass a java.io.FileReader or a jdk.nashorn.api.scripting.URLReader to load script from a file or a URL.

How to access a basic JSIL library (from C#) in a web page?

I'm trying to get started with JSIL. I've followed the directions as far as I understand. I have a very basic C# dummy project with the code:
namespace TestLib
{
public class MagicType
{
public int Multiply(int x, int y)
{ // test instance method
return x * y;
}
public static int Add(int x, int y)
{// test static int method
return x + y;
}
}
}
I've compiled this with jsilc, and created a website that hosts this along with the jsil scripts. My html initializes this:
<script type="text/javascript">
var jsilConfig = {
libraryRoot: '/js/jsil/',
scriptRoot: '/js/testlib/',
manifestRoot: '/js/testlib/',
manifests: ['TestLib.dll'] // gets as far as Loading '/js/testlib/TestLib.dll.manifest.js'...
// which is 200 / OK
};
var asm = null;
var runMain = function () { // doesn't get invoked
console.log('> main');
asm = JSIL.GetAssembly("TestLib", true); // (executed outside method) returns a stub with no content
console.log('< main');
};
</script>
<script src="/js/jsil/jsil.js"></script>
but... I can't access the library. The console output indicates that it is loading:
Loading '/js/testlib/TestLib.dll.manifest.js'...
which is a 200 OK. However, I can't access it. If I run:
var asm = JSIL.GetAssembly("TestLib", true);
then I get back a stub to the library, but it doesn't have anything in it. There's a asm.$typesByName, but that is an empty object. What I want to do (to see it work) is to call the Multiply and Add methods.
So: what am I missing? my intent is to host a transpiled library that I can access through js, which is as I understand it: possible. I just can't make it work. I have uploaded my entire test project here: https://github.com/mgravell/jsilfun
The missing piece is that JSIL's browser layer performs loading in two stages: There's the bootstrapper, which you've loaded successfully and has loaded your manifests, and then the browser scaffold, which sets up the DOM interfaces and actually executes the assemblies you've loaded. This occurs in two stages since so many things are asynchronous and you might have a reason to load additional assemblies on your own or do other work before actually running all the code.
The browser scaffold exposes a function called onLoad (yeah, sorry) that you can call to perform the second stage. The examples all do this with <body onload="onLoad()"> or something similar, but you can call it any way you want.

How to call a JS function from Java Rhino

So I've been looking and I found some other questions in stackoverflow but they weren't explained and I didn't understand much. I'm trying to execute functions from a .js file. One of the functions is:
function getRSAKey(mod, exp, pass) {
pubKey = RSA.getPublicKey(mod,exp);
encrypted = RSA.encrypt(pass, pubKey);
return encrypted;
}
As you see this function calls other functions, this is quite a big file and there's no way I can "translate" it to Java, so I have to call the .js file within it. So far I think I need to create an String with the .js file, so that's what I have in my .java file:
BufferedReader script = new BufferedReader(new FileReader("rsa.js"));
Context context = Context.enter();
ScriptableObject scope = context.initStandardObjects();
How can I do to call the function getRSAKey with some given paramaters? Also I should handle the return in the .java file!
Thanks
Edit: I forgot to say that the script uses http://silentmatt.com/biginteger/ the class provided in the link. I was able to execute a script, but it says that 'ReferenceError: "BigInteger" is not defined.'

Equivalent of Ruby's "require" in Javascript

How do you "require" another file into the existing file in Javascript? Is there anything similar to Ruby's "require" or "load"?
> Note: I'm using JS in server (Rhino)
Reason: I just need to access the methods in the other JS files.
Update: This works only when executing it from cmd line. When I try to call it programatically it fails. Here's my code: http://pastie.org/1240495
To use the load function in js embedded from Java, you must first expose it in on the scripting context. There's probably a way to do it from Java, but you can do it using js as well.
Disclaimer: this solution uses source code taken from an Apache-licensed project I have been working on. You can see the original source file here.
This js file sets up your global variables, and lives in a file named setupglobals.js:
var shell = org.mozilla.javascript.tools.shell.Main;
var args = ["-e","var a='STRING';"];
shell.exec(args);
var shellGlobal = shell.global;
//grab functions from shell global and place in current global
load=shellGlobal.load;
print=shellGlobal.print;
defineClass=shellGlobal.defineClass;
deserialize=shellGlobal.deserialize;
doctest=shellGlobal.doctest;
gc=shellGlobal.gc;
help=shellGlobal.help;
loadClass=shellGlobal.loadClass;
quit=shellGlobal.quit;
readFile=shellGlobal.readFile;
readUrl=shellGlobal.readUrl;
runCommand=shellGlobal.runCommand;
seal=shellGlobal.seal;
serialize=shellGlobal.serialize;
spawn=shellGlobal.spawn;
sync=shellGlobal.sync;
toint32=shellGlobal.toint32;
version=shellGlobal.version;
environment=shellGlobal.environment;
Here is your original Java host file, now augmented to evaluate setupglobals.js before any other scripts:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import org.mozilla.javascript.*;
public class RhinoRunner {
public static void main(String args[]) throws IOException
{
BufferedReader script = new BufferedReader(new FileReader("setupglobals.js"));
BufferedReader script2 = new BufferedReader(new FileReader("example.js"));
Context context = Context.enter();
try {
ScriptableObject scope = context.initStandardObjects();
context.evaluateReader(scope, script, "script", 1, null);
context.evaluateReader(scope, script2, "script2", 1, null);
Function fct = (Function)scope.get("abc", scope);
Object result = fct.call(context, scope, scope, new Object[] {2, 3});
System.out.println(Context.jsToJava(result, int.class));
}
finally
{
Context.exit();
}
}
}
Here is your example.js, now augmented to use the global load function to load the file hello.js:
function abc(x,y)
{
return x+y
}
load("hello.js")
And finally, here is hello.js:
print("hello world!")
When executed, RhinoRunner prints the following:
hello world!
5
In Rhino shell, you can should be able to use load(), which is a predefined global method:
load([filename, ...])
Load JavaScript source files named by string arguments. If multiple arguments are given, each file is read in and executed in turn.

Categories

Resources