]> git.basschouten.com Git - openhab-addons.git/blob
733a670ab3f2d8cd9473d288593d3b814c1b3abe
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.atlona.internal;
14
15 import java.util.Map;
16 import java.util.concurrent.ConcurrentHashMap;
17 import java.util.concurrent.locks.Lock;
18 import java.util.concurrent.locks.ReentrantLock;
19
20 import org.openhab.core.thing.ThingStatus;
21 import org.openhab.core.thing.ThingStatusDetail;
22 import org.openhab.core.types.State;
23
24 /**
25  * Defines an implementation of {@link AtlonaHandlerCallback} that will remember the last state
26  * for an channelId and suppress the callback if the state hasn't changed
27  *
28  * @author Tim Roberts - Initial contribution
29  */
30 public class StatefulHandlerCallback implements AtlonaHandlerCallback {
31
32     /** The wrapped callback */
33     private final AtlonaHandlerCallback wrappedCallback;
34
35     /** The state by channel id */
36     private final Map<String, State> state = new ConcurrentHashMap<>();
37
38     private final Lock statusLock = new ReentrantLock();
39     private ThingStatus lastThingStatus;
40     private ThingStatusDetail lastThingStatusDetail;
41
42     /**
43      * Create the callback from the other {@link AtlonaHandlerCallback}
44      *
45      * @param wrappedCallback a non-null {@link AtlonaHandlerCallback}
46      * @throws IllegalArgumentException if wrappedCallback is null
47      */
48     public StatefulHandlerCallback(AtlonaHandlerCallback wrappedCallback) {
49         if (wrappedCallback == null) {
50             throw new IllegalArgumentException("wrappedCallback cannot be null");
51         }
52
53         this.wrappedCallback = wrappedCallback;
54     }
55
56     /**
57      * Overrides the status changed to simply call the {@link #wrappedCallback}
58      *
59      * @param status the new status
60      * @param detail the new detail
61      * @param msg the new message
62      */
63     @Override
64     public void statusChanged(ThingStatus status, ThingStatusDetail detail, String msg) {
65         statusLock.lock();
66         try {
67             // Simply return we match the last status change (prevents loops if changing to the same status)
68             if (status == lastThingStatus && detail == lastThingStatusDetail) {
69                 return;
70             }
71
72             lastThingStatus = status;
73             lastThingStatusDetail = detail;
74         } finally {
75             statusLock.unlock();
76         }
77         // If we got this far - call the underlying one
78         wrappedCallback.statusChanged(status, detail, msg);
79     }
80
81     /**
82      * Overrides the state changed to determine if the state is new or changed and then
83      * to call the {@link #wrappedCallback} if it has
84      *
85      * @param channelId the channel id that changed
86      * @param state the new state
87      */
88     @Override
89     public void stateChanged(String channelId, State state) {
90         if (channelId == null || "".equals(channelId)) {
91             return;
92         }
93
94         final State oldState = this.state.get(channelId);
95
96         // If both null OR the same value (enums), nothing changed
97         if (oldState == state) {
98             return;
99         }
100
101         // If they are equal - nothing changed
102         if (oldState != null && oldState.equals(state)) {
103             return;
104         }
105
106         // Something changed - save the new state and call the underlying wrapped
107         this.state.put(channelId, state);
108         wrappedCallback.stateChanged(channelId, state);
109     }
110
111     /**
112      * Removes the state associated with the channel id. If the channelid
113      * doesn't exist (or is null or is empty), this method will do nothing.
114      *
115      * @param channelId the channel id to remove state
116      */
117     public void removeState(String channelId) {
118         if (channelId == null || "".equals(channelId)) {
119             return;
120         }
121         state.remove(channelId);
122     }
123
124     /**
125      * Overrides the set property to simply call the {@link #wrappedCallback}
126      *
127      * @param propertyName a non-null, non-empty property name
128      * @param propertyValue a non-null, possibly empty property value
129      */
130     @Override
131     public void setProperty(String propertyName, String propertyValue) {
132         wrappedCallback.setProperty(propertyName, propertyValue);
133     }
134
135     /**
136      * Callback to get the {@link State} for a given property name
137      *
138      * @param propertyName a possibly null, possibly empty property name
139      * @return the {@link State} for the propertyName or null if not found
140      */
141     public State getState(String propertyName) {
142         return state.get(propertyName);
143     }
144 }