1
votes

I have a problem loading the nashorn script engine in a Karaf+Felix+OpenJDK8 environment: new ScriptEngineManager().getEngineByName("nashorn") returns null in that environment. My tests that use that code pass successfully, no matter if executed by maven (with the same JDK Installation at tje Linux/Debian server) or inside the IDE on my Windows machine.

These are the steps I checked:

  • Karaf runs with JDK8 having the correct ext directory referenced:

    > ps aux | grep karaf | grep java
    ... -Djava.ext.dirs=/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext:/usr/lib/jvm/java-8-openjdk-amd64/lib/ext:/media/sf_Development/app/apache-karaf-4.0.6/lib/ext ...

  • The nashorn.jar is available:

    > jar -tf /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/ext/nashorn.jar | grep NashornScriptEngineFactory
    jdk/nashorn/api/scripting/NashornScriptEngineFactory.class

  • At <karaf>/etc/config.properties the org.osgi.framework.bootdelegation property contains jdk.nashorn.* according to this question

  • My bundle also imports/requires jdk.nashorn which is resolved by felix successfully:

    > bundle:requirements my-bundle | grep -A 1 nashorn
    ...
    osgi.wiring.package; (osgi.wiring.package=jdk.nashorn) resolved by:
      osgi.wiring.package; jdk.nashorn 0.0.0 from org.apache.felix.framework [0]
    ...

By the way the list returned by new ScriptEngineManager().getEngineFactories() is empty, so it's not an option to try another script engine.

Has someone any idea what went wrong? Did I need to clear some cache before restarting karaf?

1

1 Answers

2
votes

ScriptEngineManager's default constructor uses the thread context class loader with service loader mechanism. If your thread context class loader does not delegate to the extension class loader, then nashorn or any other engine visible only to extension loader will not be found! There are two solutions:

  1. You can temporarily set the thread context class loader to either extension loader or a loader that delegates to it - just before creating ScriptEngineManager object (and you set reset the old thread context class loader after finding the engine).
  2. You can use ClassLoader accepting constructor of ScriptEngineManager ( See also: https://docs.oracle.com/javase/8/docs/api/javax/script/ScriptEngineManager.html#ScriptEngineManager-java.lang.ClassLoader-) by passing an appropriate ClassLoader. Again, you can pass the extension class loader or any loader that delegates to the extension class loader - so that engines visible to extension loader can be found by service loader mechanism.