Categories
discuss

Executing a function in a specific context in Nashorn

I have a custom Nashorn runtime that I set up with some global functions and objects – some of these are stateless and some of these are stateful. Against this runtime, I am running some custom scripts.

For each execution, I am planning on creating a new context that is backed by the global context:

myContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.eval(myScript, myContext);

Based on what I read, any modifications to the global scope (from the perspective of the script) will be limited to the new context I created.

These scripts, when evaluated, expose some objects (with well-defined names and method-names). I can invoke a method on the object by casting engine to Invocable. But how do I know the context in which the function will run? Is that even an issue, or is the execution context of that function set up based on the context in which it was evaluated?

What behavior can I expect in a multithreaded situation where all threads share the same script-engine instance, and they all try to run the same script (which exposes a global object). When I then invoke the method on the object, in which context will the function run? How will it know which instance of the object to to use?

I was expecting to see an invoke method where I can specify the context, but this doesn’t seem to be the case. Is there a way to do this, or am I going about this completely wrong?

I know that an easy way to get around this is to create a new script-engine instance per execution, but as I understand, I would lose optimizations (especially on the shared code). That being said, would pre-compiling help here?

Answer

I figured this out. The problem I was running into was that invokeFunction would throw a NoSuchMethodException because the functions exposed by the custom script didn’t exist in the bindings from the engine’s default scope:

ScriptContext context = new SimpleScriptContext();
context.setBindings(nashorn.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.eval(customScriptSource, context);
((Invocable) engine).invokeFunction(name, args); //<- NoSuchMethodException thrown

So what I had to do was pull out the function from the context by name and call it explicitly like so:

JSObject function = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE);
function.call(null, args); //call to JSObject#isFunction omitted brevity 

This will call the function that exists in your newly-created context. You can also invoke methods on objects this way:

JSObject object = (JSObject) context.getAttribute(name, ScriptContext.ENGINE_SCOPE);
JSObject method = (JSObject) object.getMember(name);
method.call(object, args);

call throws an unchecked exception (either Throwable wrapped in a RuntimeException or NashornException that has been initialized with JavaScript stackframe information) so you may have to explicitly handle that if you want to provide useful feedback.

This way threads can’t step over each other because there is a separate context per thread. I was also able to share custom runtime-code between the threads and ensure that state changes to mutable-objects exposed by the custom-runtime were isolated by context.

To do this, I create a CompiledScript instance that contains a compiled representation of my custom runtime-library:

public class Runtime {

    private ScriptEngine engine;
    private CompiledScript compiledRuntime;

    public Runtime() {
        engine = new NashornScriptEngineFactory().getScriptEngine("-strict");
        String source = new Scanner(
            this.getClass().getClassLoader().getResourceAsStream("runtime/runtime.js")
        ).useDelimiter("\Z").next();

        try {
            compiledRuntime = ((Compilable) engine).compile(source);
        } catch(ScriptException e) {
            ...
        }
    }

    ...
}

Then when I need to execute a script I evaluate the compiled source, and then evaluate the script against that context as well:

ScriptContext context = new SimpleScriptContext();
context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);

//Exception handling omitted for brevity

//Evaluate the compiled runtime in our new context
compiledRuntime.eval(context); 

//Evaluate the source in the same context
engine.eval(source, context);

//Call a function
JSObject jsObject = (JSObject) context.getAttribute(function, ScriptContext.ENGINE_SCOPE);
jsObject.call(null, args);

I tested this out with multiple threads and I was able to make sure that state changes were limited to the contexts that belong to individual threads. This is because the compiled representation is executed within a specific context, which means that instances of anything exposed by it are scoped to that context.

One small disadvantage here is that you may be needlessly reevaluating object definitions for objects that don’t need to have thread-specific state. To get around this, evaluate them on the engine directly, which will add bindings for those objects to the engine’s ENGINE_SCOPE:

public Runtime() {
    ...
    String shared = new Scanner(
        this.getClass().getClassLoader().getResourceAsStream("runtime/shared.js")
    ).useDelimiter("\Z").next();

    try {
        ...        
        nashorn.eval(shared);
        ...
    } catch(ScriptException e) {
        ...
    }
}

Then later, you can populate the thread-specific context from the engine’s ENGINE_SCOPE:

context.getBindings(ScriptContext.ENGINE_SCOPE).putAll(engine.getBindings(ScriptContext.ENGINE_SCOPE));

One thing you will need to do is make sure that any such objects that you expose, have been frozen. Otherwise it is possible to redefine or add properties to them.

Categories
discuss

Using babel-cli locally

Is there a way to use the babel client without installing it globally?

So rather than this

npm install -g babel-cli

I’d like to do this

npm install babel-cli --save-dev

Answer

Any local package’s binary can be accessed inside npm scripts as if it was installed globally:

// package.json
{
   "scripts": {
     "build": "babel ..."
   }
}

If you want to execute the binary on the command line, you can use a relative path to node_modules/.bin/:

$ node_modules/.bin/babel ...

This is related to first example: node_modules/.bin/ is simple added to the PATH of the environment the npm scripts are executed in.

Categories
discuss

Are new threads automatically assigned to a different CPU Core in Java?

In Java, and more specifically, Android,
are new Threads automatically assigned to a different CPU core than the one I am currently utilizing, or should I take care of that?

Also, does it matter how the new thread is created, using the Thread class or submitting a Runnable to an Executor, that maintans a pool of threads?

There is a similar question here, but the answer goes on to explain how the OP should address his particular problem, rather than diving into the more general case:
Threads automatically utilizing multiple CPU cores?

Answer

In Java, and more specifically, Android, are new Threads automatically assigned to a different CPU core than the one I am currently utilizing, or should I take care of that?

The decision of what threads run on what cores is handled by the OS itself (in Android, based off of the Linux scheduler). You cannot affect those decisions yourself; the decisions are automatic and dynamic.

does it matter how the new thread is created, using the Thread class or submitting a Runnable to an Executor, that maintans a pool of threads?

With respect to what cores a thread runs on, the OS neither knows nor cares whether an Executor is involved, or even if the programming language that app was written in has something called Executor.

Categories
discuss

Disable image upload in Summernote

Is there any way to completely disable uploading of images in Summernote, but keep the image url input? The closest thing I found was the disableDragAndDrop: true option, but this doesn’t remove the upload button from the image pop-up

Answer

There’s probably a better way to accomplish what you’re going for… but a very simple solution that comes to mind is to just add this to your stylesheets:

.note-group-select-from-files {
  display: none;
}

It works perfectly to leave just the image url input, and accomplishes what you’re going for unless someone were to inspect element and discover that the upload element still exists with display none:

enter image description here


Edit : I took a look at the Summernote source code, and it looks like the above solution is actually a good way to go. There’s currently no api to disable just the file upload button, let alone do so while leaving the img url input intact. You could always add it and open a pull request, of course.

https://github.com/summernote/summernote/blob/4b1bf144862a88899a464ddfab6bc0593a061fbc/src/js/bs3/module/ImageDialog.js#L24

  var body = '<div class="form-group note-group-select-from-files">' +
               '<label>' + lang.image.selectFromFiles + '</label>' +
               '<input class="note-image-input form-control" type="file" name="files" accept="image/*" multiple="multiple" />' +
               imageLimitation +
             '</div>' +
             '<div class="form-group" style="overflow:auto;">' +
               '<label>' + lang.image.url + '</label>' +
               '<input class="note-image-url form-control col-md-12" type="text" />' +
             '</div>';
Categories
discuss

Is it normal that JavaScript can create otherwise invalid DOM?

Somewhat by accident, I found out that a span inserted directly inside a tbody stays in place when done with JavaScript (insertBefore), where such invalid DOM would if created with literal HTML lead to the span being placed before the entire table.

I expected either the same behaviour as with literal HTML or some DOM Exception being thrown.

E.g. this HTML

<table>
    <thead><tr><th>Table Header</th></td></thead>
    <tbody>
        <span>from HTML &rarr; goes up</span>
        <tr><td>Table Contents</td></tr>
    </tbody>
</table>

with this JavaScript:

var span = document.createElement('span'),
    tbody = document.querySelector('tbody');
span.innerHTML = 'Created with JS &rarr; stays in place';
tbody.insertBefore(span, tbody.querySelector('tr'));

renders “Created with JS → stays in place” between the header and the first row; the original, literal, span moves outside of the table.

Is this normal, and can/should I count on this? (It behaves the same in FF, Chrome, Opera, IE >= 9 (not tested below)).

Also, is there a way to query the DOM whether content of a certain type would (under normal circumstances) be valid at a certain point in the DOM? This is actually what I wanted to do when I found out about this quirk (which it is, imho).

The fiddle is here: http://jsfiddle.net/xr37g9kw/2/

Answer

As for “is this normal, and can/should I count on this?” Sadly, yes. But mostly you should be aware of the node types you are working with. NB, in case of table, there are a handful of not so well known DOM methods (HTMLTableElement.rows. InsertRow() and so on).

As for “is there a way to query the DOM whether content of a certain type would (under normal circumstances) be valid at a certain point in the DOM?” nothing built-in for this exact purpose, but you could exploit one native feature of JavaScript -> DOM API: you can let browser to re-parse HTML chunk in the “literal way”. Yes, I am speaking about innerHTML.

In your fiddle, adding**tbody.outerHTML = tbody.outerHTML** “fixes” the structure, so you could hypothetically take some DOM node, look at its DOM tree, clone, “re-eval” it and compare with original.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..