]> git.basschouten.com Git - openhab-addons.git/blob
f5d169557b8e0dacb9e86adbb6d396d60dce9394
[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.solaredge.internal.command;
14
15 import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
16
17 import java.net.CookieStore;
18 import java.net.HttpCookie;
19 import java.net.SocketTimeoutException;
20 import java.net.URI;
21 import java.net.UnknownHostException;
22 import java.nio.ByteBuffer;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.eclipse.jetty.client.HttpClient;
29 import org.eclipse.jetty.client.api.Request;
30 import org.eclipse.jetty.client.api.Response;
31 import org.eclipse.jetty.client.util.BufferingResponseListener;
32 import org.eclipse.jetty.http.HttpStatus;
33 import org.eclipse.jetty.http.HttpStatus.Code;
34 import org.openhab.binding.solaredge.internal.config.SolarEdgeConfiguration;
35 import org.openhab.binding.solaredge.internal.connector.CommunicationStatus;
36 import org.openhab.binding.solaredge.internal.connector.StatusUpdateListener;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.google.gson.Gson;
41 import com.google.gson.JsonSyntaxException;
42
43 /**
44  * base class for all commands. common logic should be implemented here
45  *
46  * @author Alexander Friese - initial contribution
47  */
48 @NonNullByDefault
49 public abstract class AbstractCommand extends BufferingResponseListener implements SolarEdgeCommand {
50
51     /**
52      * logger
53      */
54     protected final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);
55
56     /**
57      * the configuration
58      */
59     protected final SolarEdgeConfiguration config;
60
61     /**
62      * JSON deserializer
63      */
64     private final Gson gson;
65
66     /**
67      * status code of fulfilled request
68      */
69     private final CommunicationStatus communicationStatus;
70
71     /**
72      * listener to provide updates to the WebInterface class
73      */
74     private final StatusUpdateListener listener;
75
76     /**
77      * the constructor
78      *
79      * @param config
80      * @param listener
81      *
82      */
83     public AbstractCommand(SolarEdgeConfiguration config, StatusUpdateListener listener) {
84         this.communicationStatus = new CommunicationStatus();
85         this.config = config;
86         this.listener = listener;
87         this.gson = new Gson();
88     }
89
90     /**
91      * Log request success
92      */
93     @Override
94     public final void onSuccess(@Nullable Response response) {
95         super.onSuccess(response);
96         if (response != null) {
97             communicationStatus.setHttpCode(HttpStatus.getCode(response.getStatus()));
98             logger.debug("HTTP response {}", response.getStatus());
99         }
100     }
101
102     /**
103      * Log request failure
104      */
105     @Override
106     public final void onFailure(@Nullable Response response, @Nullable Throwable failure) {
107         super.onFailure(response, failure);
108         if (failure != null) {
109             logger.debug("Request failed: {}", failure.toString());
110             communicationStatus.setError((Exception) failure);
111
112             if (failure instanceof SocketTimeoutException || failure instanceof TimeoutException) {
113                 communicationStatus.setHttpCode(Code.REQUEST_TIMEOUT);
114             } else if (failure instanceof UnknownHostException) {
115                 communicationStatus.setHttpCode(Code.BAD_GATEWAY);
116             } else {
117                 communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
118             }
119         } else {
120             logger.debug("Request failed");
121         }
122     }
123
124     @Override
125     public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
126         super.onContent(response, content);
127         logger.debug("received content, length: {}", getContentAsString().length());
128     }
129
130     @Override
131     public void performAction(HttpClient asyncclient) {
132         Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
133
134         // add authentication data for every request. Handling this here makes it obsolete to implement for each and
135         // every command
136         if (config.isUsePrivateApi()) {
137             // token cookie is only used by private API therefore this can be skipped when using public API
138             CookieStore cookieStore = asyncclient.getCookieStore();
139             HttpCookie c = new HttpCookie(PRIVATE_API_TOKEN_COOKIE_NAME, config.getTokenOrApiKey());
140             c.setDomain(PRIVATE_API_TOKEN_COOKIE_DOMAIN);
141             c.setPath(PRIVATE_API_TOKEN_COOKIE_PATH);
142             cookieStore.add(URI.create(getURL()), c);
143         } else {
144             // this is only relevant when using public API
145             request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
146         }
147
148         prepareRequest(request).send(this);
149     }
150
151     /**
152      * @return returns Http Status Code
153      */
154     public CommunicationStatus getCommunicationStatus() {
155         return communicationStatus;
156     }
157
158     /**
159      * updates status of the registered listener.
160      */
161     protected final void updateListenerStatus() {
162         try {
163             listener.update(communicationStatus);
164         } catch (Exception ex) {
165             // this should not happen
166             logger.warn("Exception caught: {}", ex.getMessage(), ex);
167         }
168     }
169
170     /**
171      * concrete implementation has to prepare the requests with additional parameters, etc
172      *
173      * @param requestToPrepare the request to prepare
174      * @return prepared Request object
175      */
176     protected abstract Request prepareRequest(Request requestToPrepare);
177
178     /**
179      * concrete implementation has to provide the URL
180      *
181      * @return Url
182      */
183     protected abstract String getURL();
184
185     /**
186      * just a wrapper as fromJson could return null. This will avoid warnings as eclipse otherwise assumes unnecessary
187      * null checks which are not unnecessary
188      *
189      * @param <T>
190      * @param json
191      * @param classOfT
192      * @return
193      * @throws JsonSyntaxException
194      */
195     protected <T> @Nullable T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
196         return gson.fromJson(json, classOfT);
197     }
198 }