ClassNotFoundException: org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions

I’m trying to play with the jsr 223 scripting support and I’m stuck at using the persistence extensions. JSR 223 seems to work fine and persistence is also enabled as I can see values in my database and charts are also shown (jdbc+rrd4j), so my setup seems right.

But with this simple example.js:

'use strict';

scriptExtension.importPreset("RuleSupport");
scriptExtension.importPreset("RuleSimple");

var sRule = new SimpleRule() {
    execute: function( module, input) {
        print("## This is a 'hello world!' from a Javascript rule.");
        try
        {
            print("## PersistenceExtension: " + Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions"));
        }
        catch(e)
        {
            print("## Exception: " + e);
        }

    }
};

sRule.setTriggers([
    TriggerBuilder.create()
        .withId("aTimerTrigger")
        .withTypeUID("timer.GenericCronTrigger")
        .withConfiguration(
            new Configuration({
                "cronExpression": "0 * * * * ?"
            })).build()
    ]);

automationManager.addRule(sRule);

I get the following log:

## This is a 'hello world!' from a Javascript rule.
## Exception: java.lang.ClassNotFoundException: org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions

My setup is based on the docker image openhab/openhab 2.4.0-armhf-debian. The documentation is a little bit confusing, but I think I found evidence, that PersistenceExtensions should be available in 2.4, right?

So, what might be wrong in my setup?

Are you using the helper libraries? They make it a lot easier to use scripted automation. That link will show how to use actions.js to get to Persistence extensions. Otherwise, you will need to import it.

Unless you are very comfortable with JavaScript, I suggest using Python instead. It is much more suited for scripted automation and the helper libraries and documentation are much more evolved.

I’m fully aware of the helper libraries. I’m just curious how they work. To give you some background: I’m currently trying to implement my own JSR 223 “scripting language” and I have troubles with classloading in the JSR 223 context. I use JavaScript as Nashorn is shipped with the JDK and I can be sure everything is correct from a classloading perspective (with Groovy / Jython there is some extra complexity).

To answer the original question myself, this works:

'use strict';

scriptExtension.importPreset("RuleSupport");
scriptExtension.importPreset("RuleSimple");

print("## Initial PersistenceExtension: " + Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions"));
var sRule = new SimpleRule() {
    execute: function( module, input) {
        print("## This is a 'hello world!' from a Javascript rule.");
        try
        {
            print("## PersistenceExtension: " + Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions"));
        }
        catch(e)
        {
            print("## Exception: " + e);
        }

    }
};

sRule.setTriggers([
    TriggerBuilder.create()
        .withId("aTimerTrigger")
        .withTypeUID("timer.GenericCronTrigger")
        .withConfiguration(
            new Configuration({
                "cronExpression": "0 * * * * ?"
            })).build()
    ]);

automationManager.addRule(sRule);

It gives me:

## Initial PersistenceExtension: [JavaClass org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions]
## This is a 'hello world!' from a Javascript rule.
## JS PersistenceExtension: [JavaClass org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions]

But I don’t understand, why!? If PersistenceExtensions is loaded initially (upfront any trigger execution), the class is loaded (and cached?) and is accessible from trigger threads. But the same Classloader is not able to load the class inside the trigger code block!?

I’m not familiar with the OSGi magic of the involved EquinoxClassLoader. Seems there is still a lot to learn :-/

Is this still a problem? I ask because I have worked in this area recently. There are slight differences when the JS is invoked from the top of the script versus from a rule - this is because the java hosting code differs (and originates from a distinct OSGi bundle).

Yes and no. I found some workarounds for multiple classloading issues, so no, it’s not a problem anymore. But nevertheless I still have a bad feeling about this. Imho it should be much easier and straight forward to use OpenHAB (internal) stuff from JSR 223 scripts. There are still a lot of quirks and strange api decisions (e.g. everything around PersistenceExtensions is somehow confusing).

I’ll migrate my code to OpenHAB 2.5 in the next days. Fingers crossed it will not break all my workarounds :slight_smile: