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