archimatetool / archi-scripting-plugin

jArchi - Scripting for Archi: ArchiMate Modelling Tool
https://www.archimatetool.com
124 stars 34 forks source link

Use GraalVM instead of Nashorn #85

Closed Phillipus closed 1 year ago

Phillipus commented 3 years ago

As we know, Nashorn is deprecated and is actually removed from Java 15. There is an initiative to support it as a standalone Java module:

https://mail.openjdk.java.net/pipermail/nashorn-dev/2020-October/007557.html

However, Nashorn is quite limited for JS.

GraalVM is an alternative and supports the ECMAScript 2020 specification:

https://www.graalvm.org/reference-manual/js/JavaScriptCompatibility/

I now have this working in branch graalvm.

Select it in Preferences -> Scripting -> JavaScript Engine -> GraalVM

Caveats:

I got some scripts to work and others probably need adjusting to work properly,

For reference:

https://golb.hplar.ch/2020/04/java-javascript-engine.html https://www.graalvm.org/reference-manual/js/ScriptEngine/ https://www.graalvm.org/reference-manual/js/NashornMigrationGuide/

Phillipus commented 3 years ago

No idea of any licence restrictions

https://opensource.org/licenses/UPL

jbsarrodie commented 3 years ago

I now have this working in branch graalvm. [...] There might be things in existing jArchi scripts that don't work as expected

Is it theoretical or do you have some actual examples of things not working?

There is an initiative to support it as a standalone Java module:

That's a good news. This means that we could ship both Nashorn and GraalVM with jArchi for some time, making it clear that we'll deprecate Nashorn at some point. People would then have some time to switch to GraalVM.

Phillipus commented 3 years ago

or do you have some actual examples of things not working?

File paths are different from the __FILE__ global variable. (The "change concept type" gist uses the file path)

On Windows:

Nashorn - file:/C:/scripts/Business%20Actor.ajs GraalVM - C:\scripts\Business Actor.ajs

Maybe we should define our own global variable such as __SCRIPT_FILE__ that is bound to the script's file path in an agreed format (forward slashes only, file:/ prefix).

Phillipus commented 3 years ago

Regarding standalone Nashorn:

https://github.com/openjdk/nashorn

Nashorn is only usable as a JPMS module, so make sure it and its transitive dependencies (Nashorn depends on several ASM JARs) are on your application's module path, or appropriately added to a module layer, or otherwise configured as modules.

I have absolutely no idea how to do this for an Eclipse plug-in. Normally we simply add jar files to the runtime dependencies in Bundle-ClassPath in MANIFEST.MF file. So it anyone knows, please do tell.

Phillipus commented 3 years ago

Just a heads up that there are some differences between Nashorn and GraalVM.

For example:

https://github.com/archimatetool/archi-scripting-plugin/issues/87 https://github.com/archimatetool/archi-scripting-plugin/issues/88

The GraalVM option is experimental so if you find something that works in Nashorn but not GraalVM please experiment/debug/whatever in order to narrow it down and perhaps use an alternate idiom.

It also might be worth searching the GraalVM issues tracker - https://github.com/oracle/graaljs/issues

Phillipus commented 3 years ago

Another thing that GraalVM does differently to Nashorn is handling Java List types, and this means our EObjectProxyCollection.

For example, select two Folders in the Models tree and run:

console.log(selection);

(selection is bound to an EObjectProxyCollection.)

In Nashorn when selection is passed to console.log it is passed as a single EObjectProxyCollection object.

But in GraalVM it is an array of two FolderProxy objects.

Phillipus commented 3 years ago

So I'm re-writing the Console class to accommodate this.

jbsarrodie commented 3 years ago

But in GraalVM it is an array of two FolderProxy objects. So I'm re-writing the Console class to accommodate this.

If it's only a matter of Console displaying collection as array instead of collection that's not a big deal and doesn't need any change, no ?

BTW, in almost all my scripts, I use underscoreJS or Lodash to manipulate lists, arrays and collections. Maybe at some point it would make sens to simply rely on such JS lib instead of relying on Java List methods.

Phillipus commented 3 years ago

If it's only a matter of Console displaying collection as array instead of collection that's not a big deal and doesn't need any change, no ?

The Console does need some changes to accommodate this, and also optimised to create the total string first before appending to the text window.

Phillipus commented 3 years ago

GraalVM will determine what object type to pass depending on the method's parameters.

This is how we have Console.log in Java:

public void log(Object... objs)

GraalVM will pass an array of objects from the Selection List.

Nashorn will pass a single Selection object as the first member of an array.

If we change the method to

public void log(Object obj)

Then Nashorn and GraalVM will pass a single Selection object (a List)

Phillipus commented 3 years ago

Easy fixed by adding another method as well as public void log(Object... objs):

public void log(Object obj)

Phillipus commented 3 years ago

Regarding standalone Nashorn:

https://github.com/openjdk/nashorn

Nashorn is only usable as a JPMS module, so make sure it and its transitive dependencies (Nashorn depends on several ASM JARs) are on your application's module path, or appropriately added to a module layer, or otherwise configured as modules.

I have absolutely no idea how to do this for an Eclipse plug-in. Normally we simply add jar files to the runtime dependencies in Bundle-ClassPath in MANIFEST.MF file. So it anyone knows, please do tell.

They now distribute Nashorn in a jar. And it's possible to run Nashorn standalone on Java 15+

Discussion: https://bugs.openjdk.java.net/browse/JDK-8258216

Download: https://search.maven.org/artifact/org.openjdk.nashorn/nashorn-core

Dependencies: https://search.maven.org/search?q=g:org.ow2.asm (asm, asm-util, and asm-commons)

New branch: nashorn-standalone

Phillipus commented 3 years ago

(Note to self)

GraalVM dependencies:

Jar Maven
graal-sdk-20.3.0.jar https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk
js-20.3.0.jar https://mvnrepository.com/artifact/org.graalvm.js/js
js-scriptengine-20.3.0.jar https://mvnrepository.com/artifact/org.graalvm.js/js-scriptengine
regex-20.3.0.jar https://mvnrepository.com/artifact/org.graalvm.regex/regex
truffle-api-20.3.0.jar https://mvnrepository.com/artifact/org.graalvm.truffle/truffle-api
icu4j-67.1 https://mvnrepository.com/artifact/com.ibm.icu/icu4j

Eclipse ships with icu4j (com.ibm.icu_67.1.0.v20200706-1749.jar) so we get that shipped with Archi as long as we add com.ibm.icu to the dependencies of MANIFEST.MF. However, see https://www.eclipse.org/eclipse/news/4.19/platform_isv.php#icu-e4-feature so we have to keep our eye on that. If ever it's removed from Eclipse, we can ship our own jar.

Phillipus commented 2 years ago

A useful link for dependencies:

https://www.graalvm.org/22.2/reference-manual/js/RunOnJDK/

Phillipus commented 2 years ago

Eclipse ships with icu4j (com.ibm.icu_67.1.0.v20200706-1749.jar) so we get that shipped with Archi as long as we add com.ibm.icu to the dependencies of MANIFEST.MF. If ever it's removed from Eclipse, we can ship our own jar.

And this creates a problem. Adding icu4j-67.1.jar from maven to the Runtime Classpath causes the com.archimatetool.script bundle to load before the Workbench is running, even when none of its views are open. I think this is because an EMF Eclipse plug-in uses icu4j and Eclipse is searching all bundles to resolve a class from it.

See https://bugs.eclipse.org/bugs/show_bug.cgi?id=580569

Edit: fixed in Eclipse 4.25