]> git.basschouten.com Git - openhab-addons.git/blob
d0aefd569c60470acbdc6afb1d58ba0b31107501
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.velux.internal.bridge;
14
15 import java.util.Collections;
16 import java.util.Set;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.openhab.binding.velux.internal.bridge.common.BridgeAPI;
20 import org.openhab.binding.velux.internal.bridge.common.BridgeCommunicationProtocol;
21 import org.openhab.binding.velux.internal.bridge.common.Login;
22 import org.openhab.binding.velux.internal.bridge.common.Logout;
23 import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * 2nd Level I/O interface towards the <B>Velux</B> bridge.
29  * It provides methods for pre- and post-communication
30  * as well as a common method for the real communication.
31  * The following class access methods exist:
32  * <UL>
33  * <LI>{@link VeluxBridge#bridgeLogin} for pre-communication,</LI>
34  * <LI>{@link VeluxBridge#bridgeLogout} for post-communication,</LI>
35  * <LI>{@link VeluxBridge#bridgeCommunicate} as method for the common communication.</LI>
36  * </UL>
37  * <P>
38  * Each protocol-specific implementation provides a publicly visible
39  * set of supported protocols as variable {@link #supportedProtocols}.
40  * As root of several inheritance levels it predefines an
41  * interfacing method {@link VeluxBridge#bridgeAPI} which
42  * has to be implemented by any kind of protocol-specific
43  * communication returning the appropriate base (1st) level
44  * communication method as well as any other gateway
45  * interaction with {@link #bridgeDirectCommunicate}.
46  *
47  * @author Guenther Schreiner - Initial contribution.
48  */
49 @NonNullByDefault
50 public abstract class VeluxBridge {
51     private final Logger logger = LoggerFactory.getLogger(VeluxBridge.class);
52
53     /*
54      * ***************************
55      * ***** Private Objects *****
56      */
57
58     private final String emptyAuthenticationToken = "";
59
60     // Type definitions, variables
61
62     /**
63      * Support protocols for the concrete implementation.
64      * <P>
65      * For protocol-specific implementations this value has to be adapted along the inheritance i.e.
66      * with the protocol-specific class values.
67      */
68     public Set<String> supportedProtocols = Collections.emptySet();
69
70     /** BridgeCommunicationProtocol authentication token for Velux Bridge. */
71     protected String authenticationToken = emptyAuthenticationToken;
72
73     /**
74      * Handler to access global bridge instance methods
75      *
76      */
77     protected VeluxBridgeHandler bridgeInstance;
78
79     /*
80      * ************************
81      * ***** Constructors *****
82      */
83
84     /**
85      * Constructor.
86      * <P>
87      * Initializes the binding-wide instance for dealing with common informations and
88      * the Velux bridge connectivity settings by preparing the configuration settings with help
89      * by VeluxBridgeConfiguration.
90      *
91      * @param bridgeInstance refers to the binding-wide instance for dealing for common informations
92      *            like existing actuators and predefined scenes.
93      */
94     public VeluxBridge(VeluxBridgeHandler bridgeInstance) {
95         logger.trace("VeluxBridge(constructor,bridgeInstance={}) called.", bridgeInstance);
96         this.bridgeInstance = bridgeInstance;
97         logger.trace("VeluxBridge(constructor) done.");
98     }
99
100     // Destructor methods
101
102     /**
103      * Destructor.
104      * <P>
105      * Deinitializes the binding-wide instance.
106      *
107      */
108     public void shutdown() {
109         logger.trace("shutdown() called.");
110     }
111
112     // Class access methods
113
114     /**
115      * Determines whether the binding is already authenticated against the bridge so that
116      * any other communication can occur without an additional care about authentication.
117      * <P>
118      * This method automatically decides on availability of the stored authentication
119      * information {@link VeluxBridge#authenticationToken} whether a (re-)authentication is possible.
120      *
121      * @return true if the bridge is authenticated; false otherwise.
122      */
123     private boolean isAuthenticated() {
124         boolean success = (authenticationToken.length() > 0);
125         logger.trace("isAuthenticated() returns {}.", success);
126         return success;
127     }
128
129     /**
130      * Declares the binding as unauthenticated against the bridge so that the next
131      * communication will take care about (re-)authentication.
132      */
133     protected void resetAuthentication() {
134         logger.trace("resetAuthentication() called.");
135         authenticationToken = emptyAuthenticationToken;
136         return;
137     }
138
139     /**
140      * Prepare an authorization request and communicate it with the <b>Velux</b> veluxBridge.
141      * If login is successful, the returned authorization token will be stored within this class
142      * for any further communication via {@link#bridgeCommunicate} up
143      * to an authorization with method {@link VeluxBridge#bridgeLogout}.
144      *
145      * @return true if the login was successful, and false otherwise.
146      */
147     public synchronized boolean bridgeLogin() {
148         logger.trace("bridgeLogin() called.");
149
150         Login bcp = bridgeAPI().login();
151         bcp.setPassword(bridgeInstance.veluxBridgeConfiguration().password);
152         if (bridgeCommunicate(bcp, false)) {
153             logger.trace("bridgeLogin(): communication succeeded.");
154             if (bcp.isCommunicationSuccessful()) {
155                 logger.trace("bridgeLogin(): storing authentication token for further access.");
156                 authenticationToken = bcp.getAuthToken();
157                 return true;
158             }
159         }
160         return false;
161     }
162
163     /**
164      * Prepare an authenticated deauthorization request and communicate it with the <b>Velux</b> veluxBridge.
165      * The authorization token stored in this class will be destroyed, so that the
166      * next communication has to start with {@link VeluxBridge#bridgeLogin}.
167      *
168      * @return true if the logout was successful, and false otherwise.
169      */
170     public synchronized boolean bridgeLogout() {
171         logger.trace("bridgeLogout() called: emptying authentication token.");
172         authenticationToken = "";
173
174         Logout bcp = bridgeAPI().logout();
175         if (bridgeCommunicate(bcp, false)) {
176             logger.trace("bridgeLogout(): communication succeeded.");
177             if (bcp.isCommunicationSuccessful()) {
178                 logger.trace("bridgeLogout(): logout successful.");
179                 return true;
180             }
181         }
182         return false;
183     }
184
185     /**
186      * Initializes a client/server communication towards <b>Velux</b> veluxBridge
187      * based on the Basic I/O interface {@link VeluxBridge} and parameters
188      * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
189      *
190      * @param communication the intended communication,
191      *            that is request and response interactions as well as appropriate URL definition.
192      * @param useAuthentication whether to use authenticated communication.
193      * @return true if communication was successful, and false otherwise.
194      */
195     private synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication,
196             boolean useAuthentication) {
197         logger.trace("bridgeCommunicate({},{}authenticated) called.", communication.name(),
198                 useAuthentication ? "" : "un");
199
200         if (!isAuthenticated()) {
201             if (useAuthentication) {
202                 logger.trace("bridgeCommunicate(): no auth token available, aborting.");
203                 return false;
204             } else {
205                 logger.trace("bridgeCommunicate(): no auth token available, continuing.");
206             }
207         }
208         return bridgeDirectCommunicate(communication, useAuthentication);
209     }
210
211     /**
212      * Initializes a client/server communication towards <b>Velux</b> Bridge
213      * based on the Basic I/O interface {@link VeluxBridge} and parameters
214      * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
215      * This method automatically decides to invoke a login communication before the
216      * intended request if there has not been an authentication before.
217      *
218      * @param communication the intended communication, that is request and response interactions as well as appropriate
219      *            URL definition.
220      * @return true if communication was successful, and false otherwise.
221      */
222     public synchronized boolean bridgeCommunicate(BridgeCommunicationProtocol communication) {
223         logger.trace("bridgeCommunicate({}) called.", communication.name());
224         if (!isAuthenticated()) {
225             bridgeLogin();
226         }
227         return bridgeCommunicate(communication, true);
228     }
229
230     /**
231      * Returns the timestamp in milliseconds since Unix epoch
232      * of last communication.
233      * <P>
234      * If possible, it should be overwritten by protocol specific implementation.
235      * </P>
236      *
237      * @return timestamp (default zero).
238      */
239     public long lastCommunication() {
240         logger.trace("lastCommunication() returns zero.");
241         return 0L;
242     }
243
244     /**
245      * Returns the timestamp in milliseconds since Unix epoch
246      * of last successful communication.
247      * <P>
248      * If possible, it should be overwritten by protocol specific implementation.
249      * </P>
250      *
251      * @return timestamp (default zero).
252      */
253     public long lastSuccessfulCommunication() {
254         logger.trace("lastSuccessfulCommunication() returns zero.");
255         return 0L;
256     }
257
258     /**
259      * Provides information about the base-level communication method and
260      * any kind of available gateway interaction.
261      * <P>
262      * For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
263      * with the protocol-specific class implementations.
264      *
265      * @return bridgeAPI of type {@link org.openhab.binding.velux.internal.bridge.common.BridgeAPI BridgeAPI}.
266      */
267     public abstract BridgeAPI bridgeAPI();
268
269     /**
270      * Initializes a client/server communication towards <b>Velux</b> veluxBridge
271      * based on the protocol-specific implementations with common parameters
272      * passed as arguments (see below) and provided by VeluxBridgeConfiguration.
273      * <P>
274      * For protocol-specific implementations this method has to be overwritten along the inheritance i.e.
275      * with the protocol-specific class implementations.
276      *
277      * @param communication Structure of interface type {@link BridgeCommunicationProtocol} describing the
278      *            intended communication.
279      * @param useAuthentication boolean flag to decide whether to use authenticated communication.
280      * @return <b>success</b> of type boolean which signals the success of the communication.
281      */
282     protected abstract boolean bridgeDirectCommunicate(BridgeCommunicationProtocol communication,
283             boolean useAuthentication);
284
285     /**
286      * Check is the last communication was a good one
287      *
288      * @return true if the last communication was a good one
289      */
290     public boolean lastCommunicationOk() {
291         return lastCommunication() != 0 && lastSuccessfulCommunication() == lastCommunication();
292     }
293 }