My Goal:
I'm building a "plugin" for Apache Unomi, which seems to be a pretty standard set of Karaf / OSGi services. As part of this, I'd like to be able to execute Javascript (and eventually Nodejs) from inside my Java code, and the best option moving forward seems to be GraalVM (I'm not interested in using anything legacy like Nashorn/Rhino). My current work in progress is in this PR on my fork of Unomi.
My Issue:
I'm unable to get GraalVM Polyglot code working inside a Karaf module. Adding Maven dependencies fails at runtime, and manually adding the class (that the GraalVM runtime should provide) into my framework config file throws an error about no additional languages available.
What I've Done So Far:
I've successfully installed GraalVM for JDK 11 (OS X Catalina)
% java -version
openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02)
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (build 11.0.6+9-jvmci-20.0-b02, mixed mode, sharing)
I've referenced the GraalVM tutorial for Maven on JDK 11 and added the following to my plugin's pom based on the example:
<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<version>20.0.0</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>20.0.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>20.0.0</version>
</dependency>
I've also added some sample code per the GraalVM documentation to my plugin:
Context polyglot = Context.create();
Value array = polyglot.eval("js", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
What Happens (Fails):
At this point, my Maven build completes without errors. When I start Karaf, however, I immediately get an error (full output):
Unable to resolve root: missing requirement [root] osgi.identity; osgi.identity=unomi-router-karaf-feature; type=karaf.feature; version="[1.5.0.SNAPSHOT,1.5.0.SNAPSHOT]"; filter:="(&(osgi.identity=unomi-router-karaf-feature)(type=karaf.feature)(version>=1.5.0.SNAPSHOT)(version<=1.5.0.SNAPSHOT))" [caused by: Unable to resolve unomi-router-karaf-feature/1.5.0.SNAPSHOT: missing requirement [unomi-router-karaf-feature/1.5.0.SNAPSHOT] osgi.identity; osgi.identity=org.apache.unomi.router-rest; type=osgi.bundle; version="[1.5.0.SNAPSHOT,1.5.0.SNAPSHOT]"; resolution:=mandatory [caused by: Unable to resolve org.apache.unomi.router-rest/1.5.0.SNAPSHOT: missing requirement [org.apache.unomi.router-rest/1.5.0.SNAPSHOT] osgi.service; effective:=active; filter:="(&(objectClass=org.apache.unomi.router.api.services.ImportExportConfigurationService)(configDiscriminator=IMPORT))" [caused by: Unable to resolve org.apache.unomi.router-service/1.5.0.SNAPSHOT: missing requirement [org.apache.unomi.router-service/1.5.0.SNAPSHOT] osgi.wiring.package; filter:="(&(osgi.wiring.package=org.apache.unomi.persistence.spi)(version>=1.5.0)(!(version>=2.0.0)))" [caused by: Unable to resolve org.apache.unomi.persistence-spi/1.5.0.SNAPSHOT: missing requirement [org.apache.unomi.persistence-spi/1.5.0.SNAPSHOT] osgi.identity; osgi.identity="root#unomi-kar-1.5.0.SNAPSHOT"; type=karaf.subsystem; version="[0,0.0.0]"; resolution:=mandatory [caused by: Unable to resolve root#unomi-kar-1.5.0.SNAPSHOT: missing requirement [root#unomi-kar-1.5.0.SNAPSHOT] osgi.identity; osgi.identity=unomi-kar; type=karaf.feature; version="[1.5.0.SNAPSHOT,1.5.0.SNAPSHOT]" [caused by: Unable to resolve unomi-kar/1.5.0.SNAPSHOT: missing requirement [unomi-kar/1.5.0.SNAPSHOT] osgi.identity; osgi.identity=org.apache.unomi.plugins-firstparty; type=osgi.bundle; version="[1.5.0.SNAPSHOT,1.5.0.SNAPSHOT]"; resolution:=mandatory [caused by: Unable to resolve org.apache.unomi.plugins-firstparty/1.5.0.SNAPSHOT: missing requirement [org.apache.unomi.plugins-firstparty/1.5.0.SNAPSHOT] osgi.wiring.package; filter:="(osgi.wiring.package=com.ibm.icu.impl)"]]]]]]]
If I remove the three dependencies from my plugin's pom and rebuild, I can start Karaf without issue. However, when I try and run my action in my Unomi plugin, it immediately says there's no graalvm polyglot class available (expected).
After some googling, I stumbled upon an existing GitHub issue, and followed the suggestion to add org.graalvm.polyglot
to org.osgi.framework.system.packages.extra
. This almost worked, but now when I try and run my action in my Unomi plugin, I get a PolyglotIllegalArgumentException: A language with id 'js' is not installed. Installed languages are: [].
I then tried adding all of the classes I attempted including in the pom above in this manner, but it continued to return the same error.
I'm unsure of where to go from here. I'm guessing my inexperience with Maven is going to point out that this is a stupid problem, though after a lot of searching it appears that the small amount of content available around running GraalVM on OSGi all points to it possibly not working - though I have to imagine this is possible. My thoughts on a potential solution are
- I've configured my Maven pom poorly, and there's a way to solve this through a properly configured pom
- I need to specify additional system packages in
org.osgi.framework.system.packages.extra
beyond the singleorg.graalvm.polyglot
, but am unsure of how to move forward here.
Any assistance is beyond appreciated!