2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.russound.internal.rio;
16 import java.util.Objects;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.locks.Lock;
19 import java.util.concurrent.locks.ReentrantLock;
21 import org.openhab.core.thing.ThingStatus;
22 import org.openhab.core.thing.ThingStatusDetail;
23 import org.openhab.core.types.State;
26 * Defines an implementation of {@link RioHandlerCallback} that will remember the last state
27 * for a channelId and suppress the callback if the state hasn't changed
29 * @author Tim Roberts - Initial contribution
31 public class StatefulHandlerCallback implements RioHandlerCallback {
33 /** The wrapped callback */
34 private final RioHandlerCallback wrappedCallback;
36 /** The state by channel id */
37 private final Map<String, State> state = new ConcurrentHashMap<>();
39 private final Lock statusLock = new ReentrantLock();
40 private ThingStatus lastThingStatus = null;
41 private ThingStatusDetail lastThingStatusDetail = null;
44 * Create the callback from the other {@link RioHandlerCallback}
46 * @param wrappedCallback a non-null {@link RioHandlerCallback}
47 * @throws IllegalArgumentException if wrappedCallback is null
49 public StatefulHandlerCallback(RioHandlerCallback wrappedCallback) {
50 if (wrappedCallback == null) {
51 throw new IllegalArgumentException("wrappedCallback cannot be null");
54 this.wrappedCallback = wrappedCallback;
58 * Overrides the status changed to simply call the {@link #wrappedCallback}
60 * @param status the new status
61 * @param detail the new detail
62 * @param msg the new message
65 public void statusChanged(ThingStatus status, ThingStatusDetail detail, String msg) {
68 // Simply return we match the last status change (prevents loops if changing to the same status)
69 if (status == lastThingStatus && detail == lastThingStatusDetail) {
73 lastThingStatus = status;
74 lastThingStatusDetail = detail;
79 // If we got this far - call the underlying one
80 wrappedCallback.statusChanged(status, detail, msg);
84 * Overrides the state changed to determine if the state is new or changed and then
85 * to call the {@link #wrappedCallback} if it has
87 * @param channelId the channel id that changed
88 * @param newState the new state
91 public void stateChanged(String channelId, State newState) {
92 if (channelId == null || channelId.isEmpty()) {
96 final State oldState = state.get(channelId);
98 // If they are equal - nothing changed
99 if (Objects.equals(oldState, newState)) {
103 // Something changed - save the new state and call the underlying wrapped
104 state.put(channelId, newState);
105 wrappedCallback.stateChanged(channelId, newState);
109 * Removes the state associated with the channel id. If the channelid
110 * doesn't exist (or is null or is empty), this method will do nothing.
112 * @param channelId the channel id to remove state
114 public void removeState(String channelId) {
115 if (channelId == null || channelId.isEmpty()) {
118 state.remove(channelId);
122 * Overrides the set property to simply call the {@link #wrappedCallback}
124 * @param propertyName a non-null, non-empty property name
125 * @param propertyValue a non-null, possibly empty property value
128 public void setProperty(String propertyName, String propertyValue) {
129 wrappedCallback.setProperty(propertyName, propertyValue);
133 * Returns teh current state for the property
135 * @param propertyName a possibly null, possibly empty property name
136 * @return the {@link State} for the property or null if not found (or property name is null/empty)
138 public State getProperty(String propertyName) {
139 return state.get(propertyName);
143 public void addListener(String channelId, RioHandlerCallbackListener listener) {
144 wrappedCallback.addListener(channelId, listener);
148 public void removeListener(String channelId, RioHandlerCallbackListener listener) {
149 wrappedCallback.removeListener(channelId, listener);