I am running Java program on Graal JVM (graalvm-ce-java8-19.3.0), and inside that program I run JS scripts via Graal.js engine. I want to configure remote debugging connection for that JS script (not the Java program). I already found that Graal has support for that kind of debugging via Chrome DevTools protocol/standard.
Documentation explains how to use standalone Graal.js interpreter, but it also says that you can use same options in JVM by prefixing them with -Dpolyglot
.
So instead of --inspect
you need to use -Dpolyglot.inspect
:
java -Dpolyglot.inspect=9229 -jar app.jar
And this works perfect for local debugging - all as described here and here.
Now I tried to use the same for remote debugging, by setting -Dpolyglot.inspect=exampleHost:9229
, where exampleHost resolves to my external ip. Unfortunately this setting prevents Graal.js engine to initialize correctly. There is not much indication on what is really wrong, just this msg on stderr:
ScriptEngineManager providers.next(): javax.script.ScriptEngineFactory:
Provider com.oracle.truffle.js.scriptengine.GraalJSEngineFactory could not be instantiated
Does it mean that remote configuration is not supported? What is wrong here?
It turns out that for remote connections Graal by default wants to use a secure debugging channel, so you need to either disable that by -Dpolyglot.inspect.Secure=false
or configure properly using -Dpolyglot.inspect.KeyStore*
switches.
As for my case that security was not needed, so my config became:
java -Dpolyglot.inspect=exampleHost:9229 -Dpolyglot.inspect.Secure=false -jar app.jar
I just had to add exampleHost:9229 to chrome://inspect/#devices -> Configure...
And remote debugging works!
TL;DR
Here is how I found the reason of configuration problem. It may be useful in other similar cases.
I debugged the problematic Java program to see what kind of problem occurs in that ScriptEngineManager
, I put a breakpoint in javax.script.ScriptEngineManager#initEngines in line containing message "ScriptEngineManager providers.next():". It turned out that this class has an internal DEBUG constant hard-coded to false, which prevents printing any stacktraces to stderr. I dumped the exception manually to stderr:
oracle.truffle.js.scriptengine.GraalJSEngineFactory could not be instantiated
at java.util.ServiceLoader.fail(ServiceLoader.java:232)
at java.util.ServiceLoader.access$100(ServiceLoader.java:185)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:384)
at java.util.ServiceLoader$LazyIterator.access$700(ServiceLoader.java:323)
at java.util.ServiceLoader$LazyIterator$2.run(ServiceLoader.java:407)
at java.security.AccessController.doPrivileged(Native Method)
at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:409)
at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
at javax.script.ScriptEngineManager.initEngines(ScriptEngineManager.java:122)
at javax.script.ScriptEngineManager.init(ScriptEngineManager.java:84)
at javax.script.ScriptEngineManager.<init>(ScriptEngineManager.java:61)
...
Caused by: org.graalvm.polyglot.PolyglotException: Starting inspector on exampleHost:9229 failed: Use options to specify the keystore
at org.graalvm.polyglot.Engine$Builder.build(Engine.java:506)
at com.oracle.truffle.js.scriptengine.GraalJSEngineFactory.<init>(GraalJSEngineFactory.java:95)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:380)
... 17 more
Now this was just a matter of finding out how to set or disable that required keystore.