Locks in Openhab 2.4+ (Rules stopped working)

Hi!

I’ve noticed problems with my rules since upgrading openhab. I found out this was related to how I use locks.

For instance (motion sensor to turn on a dimmer).

rule "TurnLightsMBathroom"
when
    Item ZwaveEye3Motion changed to ON
then
  logInfo("MBathroom", "Motion Triggered in MBathroom")
  if (mMBathroomMotionLock === null) {
         mMBathroomMotionLock = new ReentrantLock()
    }
    mMBathroomMotionLock.lock()
    try {
          val Number currentDimLevel = ZwaveMBathRoomDimmerDim.state as DecimalType
          logInfo("Bathroom", "Current DimLevel: " + currentDimLevel)
    }    finally { mMBathroomMotionLock.unlock() }
end

What happens here is I get a null pointer from ZwaveMBathRoomDimmerDim.state as DecimalType resulting in:

Could not cast NULL to org.eclipse.smarthome.core.library.types.DecimalType.

The finally statement is never invoked and the lock is never released. Anyone know why?
Also using try catch around the ZwaveMBathRoomDimmerDim.state as DecimalType does not work either.

Any suggestions on how to use the lock in a safe manner?

Regards, Seaside

It’s a well known weakness in the rules DSL try-catch-finally.

Solution, don’t allow errors in your locked code. Test for NULL state before casting, etc.

I guess it’s just an example, by whyever would you use a lock in this rule? It is worth reviewing in your real rules.

Try this if you get an error:

rule "TurnLightsMBathroom"
when
    Item ZwaveEye3Motion changed to ON
then
    logInfo("MBathroom", "Motion Triggered in MBathroom")

    //if (mMBathroomMotionLock === null) {
    //       mMBathroomMotionLock = new ReentrantLock()
    //}
    //mMBathroomMotionLock.lock()
    //try {

    if (ZwaveMBathRoomDimmerDim.state != UNDEF && ZwaveMBathRoomDimmerDim.state != NULL) {
          val Number currentDimLevel = ZwaveMBathRoomDimmerDim.state as DecimalType
          logInfo("Bathroom", "Current DimLevel: " + currentDimLevel)
    }

    //}    finally { mMBathroomMotionLock.unlock() }
end

Hi!

Thanks for the reply.
Well I understand what to do to avoid the exception like you pointed out.
In this example I might not even need a lock, but I want to a more robust approach towards locks.
Getting exceptions is ok, but not releasing the lock while getting exception is not optimal.

Regards, S

But you shouldn’t need lock in the first place.
They are only needed in a few rare cases

I have a few cases when I need them.
But if there are no means to catch faults and make it a bit more robust, then that’s unfortunate but still something I can live with.

1 Like

Just for some background.

As said, locks are not safe to use in Rules DSL. If you experience a type error in the try clause (in this case you tried to cast a NULL to a Number), the exception is generated, and caught outside your Rule code by the language interpreter and your finally clause never executes.

Only use locks when you really really really need to and you have exhausted each and every possible alternative you can think of to avoid their use. For example, see the Queue example in Design Pattern: Gate Keeper that let’s you “borrow” the locks from the Java class ConcurrentLinkedQueue which don’t get stuck because there is no code from your Rule inside the locked segment.

Thanks for the info guys. I will probably have some redesign to do, I’ll see if I can avoid the locks.

Regards S

If you can’t you should consider looking into JSR223 Rules. The Jython Rules with the helper libraries make for very easy to write Rules but you get the full support of a “real” programming language. I think Rules DSL is great for most uses, but if you has situations where timing is vital or you just have to use locks, Rules DSL will give you trouble.

1 Like