openhab-scripters / openhab-helper-libraries

Scripts and modules for use with openHAB
Eclipse Public License 1.0
88 stars 68 forks source link

_DirectoryEventTriggerHandlerFactory doesn't work #348

Closed hemagi closed 3 years ago

hemagi commented 3 years ago

Describe the bug The _DirectoryEventTriggerHandlerFactory in 100_DirectoryTrigger.py and therefore the DirectoryEventTrigger doesn't work at all and, after fix, does not provide the necessary information in the event.

To Reproduce In a module I defined a helper class with some triggers, i.e.

from core.triggers import DirectoryEventTrigger
from core.jsr223.scope import SimpleRule
...
class OwnRule(SimpleRule):
    def watch_directory(self,path):
            self.triggers.append(DirectoryEventTrigger(path).trigger)

    ...

Using this trigger and after adding a file to the watched directory one gets:

2020-07-31 09:13:03.932 [ERROR] [ore.common.registry.AbstractRegistry] - Cannot inform the listener "org.openhab.core.automation.internal.RuleEngineImpl$2@30c355fe" about the "ADDED" event: NotImplementedError: 'Handler' object does not implement abstract method 'setCallback' from 'org.openhab.core.automation.handler.ModuleHandler'
org.python.core.PyException: NotImplementedError: 'Handler' object does not implement abstract method 'setCallback' from 'org.openhab.core.automation.handler.ModuleHandler'
    at org.python.core.Py.NotImplementedError(Py.java:140) ~[?:2.7.2]
    at org.python.compiler.ProxyCodeHelpers.notImplementedAbstractMethod(ProxyCodeHelpers.java:97) ~[?:2.7.2]
    at org.python.proxies.__main__$Handler$1.setCallback(Unknown Source) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.lambda$0(RuleEngineImpl.java:642) ~[?:?]
    at java.util.ArrayList.forEach(ArrayList.java:1259) ~[?:1.8.0_262]
    at java.util.Collections$UnmodifiableCollection.forEach(Collections.java:1082) ~[?:1.8.0_262]
    at org.openhab.core.automation.internal.RuleEngineImpl.register(RuleEngineImpl.java:639) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.activateRule(RuleEngineImpl.java:856) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.setRule(RuleEngineImpl.java:504) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl.addRule(RuleEngineImpl.java:464) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl$2.added(RuleEngineImpl.java:272) ~[?:?]
    at org.openhab.core.automation.internal.RuleEngineImpl$2.added(RuleEngineImpl.java:1) ~[?:?]
        ...

I fixed this in 100_DirectoryTrigger.py by adding

        def setCallback(self, callback):
            self.rule_engine_callback = callback

to

    class Handler(TriggerHandler):

        @log_traceback
        def __init__(self, trigger):
            TriggerHandler.__init__(self)
            self.rule_engine_callback = None
            self.trigger = trigger
            config = trigger.configuration
            self.watcher = JythonDirectoryWatcher(
                config.get('path'), eval(config.get('event_kinds')),
                watch_subdirectories=config.get('watch_subdirectories'))
            self.watcher.callback = self.handle_directory_event
            self.watcher.activate()

        def setRuleEngineCallback(self, rule_engine_callback):
            self.rule_engine_callback = rule_engine_callback

(the latter method setRuleEngineCallback() was never called and should be removable).

After this one gets not the expected event, because only the 'event' entry is taken from the callback parameters.

Therefore I replaced

        @log_traceback
        def handle_directory_event(self, event, kind, path):
            self.rule_engine_callback.triggered(self.trigger, {
                'event': event,
                'kind': kind,
                'path': path
            })

by

        @log_traceback
        def handle_directory_event(self, event, kind, path):
        self.rule_engine_callback.triggered(self.trigger, {
                'event': { 'kind': kind,
                           'path': path,
                         }
            })

At the end the handler became

class _DirectoryEventTriggerHandlerFactory(TriggerHandlerFactory):

    class Handler(TriggerHandler):

        @log_traceback
        def __init__(self, trigger):
            TriggerHandler.__init__(self)
            self.rule_engine_callback = None
            self.trigger = trigger
            config = trigger.configuration
            self.watcher = JythonDirectoryWatcher(
                config.get('path'), eval(config.get('event_kinds')),
                watch_subdirectories=config.get('watch_subdirectories'))
            self.watcher.callback = self.handle_directory_event
            self.watcher.activate()

        def setCallback(self, callback):
            self.rule_engine_callback = callback

        @log_traceback
        def handle_directory_event(self, event, kind, path):
        self.rule_engine_callback.triggered(self.trigger, {
                'event': { 'kind': kind,
                           'path': path,
                         }
            })

        def dispose(self):
            self.watcher.deactivate()
            self.watcher = None

    def get(self, trigger):
        return _DirectoryEventTriggerHandlerFactory.Handler(trigger)

in order to work as expected.

Environment (please complete the following information):

5iver commented 3 years ago

I've stated several times here and in the forum that this has been broken, along with the OSGIEvent Trigger, since OH 2.4 S1319. I have an update with fixes and will compare them to what you have put together before I push. Thank you!

hemagi commented 3 years ago

Potentially it is better to implement

        @log_traceback
        def handle_directory_event(self, event, kind, path):
        self.rule_engine_callback.triggered(self.trigger, {
                'event': { 'event' : event,
                           'kind': str(kind),
                           'path': str(path),
                         }
            })
  1. Maybe someone is interested in the event itself
  2. The kind and path should be returned pythonic, not as Java objects
5iver commented 3 years ago

Resolved in #368 and added to core.triggers in #373.