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.solaredge.internal.callback;
15 import static org.openhab.binding.solaredge.internal.SolarEdgeBindingConstants.*;
17 import java.net.CookieStore;
18 import java.net.HttpCookie;
19 import java.net.SocketTimeoutException;
21 import java.net.UnknownHostException;
22 import java.nio.ByteBuffer;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
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;
41 import com.google.gson.Gson;
42 import com.google.gson.JsonSyntaxException;
45 * base class for all commands. common logic should be implemented here
47 * @author Alexander Friese - initial contribution
50 public abstract class AbstractCommandCallback extends BufferingResponseListener implements SolarEdgeCommand {
55 protected final Logger logger = LoggerFactory.getLogger(AbstractCommandCallback.class);
60 protected final SolarEdgeConfiguration config;
65 private final Gson gson;
68 * status code of fulfilled request
70 private final CommunicationStatus communicationStatus;
73 * listener to provide updates to the WebInterface class
75 private @Nullable StatusUpdateListener listener;
82 public AbstractCommandCallback(SolarEdgeConfiguration config) {
83 this.communicationStatus = new CommunicationStatus();
85 this.gson = new Gson();
93 public AbstractCommandCallback(SolarEdgeConfiguration config, StatusUpdateListener listener) {
95 this.listener = listener;
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());
111 * Log request failure
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);
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);
125 communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
128 logger.debug("Request failed");
133 public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
134 super.onContent(response, content);
135 logger.debug("received content, length: {}", getContentAsString().length());
139 public void performAction(HttpClient asyncclient) {
140 Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
142 // add authentication data for every request. Handling this here makes it obsolete to implement for each and
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);
152 // this is only relevant when using public API
153 request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
157 prepareRequest(request).send(this);
161 * @return returns Http Status Code
163 public CommunicationStatus getCommunicationStatus() {
164 return communicationStatus;
168 public void updateListenerStatus() {
169 if (listener != null) {
170 listener.update(communicationStatus);
175 * concrete implementation has to prepare the requests with additional parameters, etc
177 * @param requestToPrepare the request to prepare
178 * @return prepared Request object
180 protected abstract Request prepareRequest(Request requestToPrepare);
183 * concrete implementation has to provide the URL
187 protected abstract String getURL();
190 public final void setListener(StatusUpdateListener listener) {
191 this.listener = listener;
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
202 * @throws JsonSyntaxException
204 protected <T> @Nullable T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
205 return gson.fromJson(json, classOfT);