2 * Copyright (c) 2010-2024 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.command;
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.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;
40 import com.google.gson.Gson;
41 import com.google.gson.JsonSyntaxException;
44 * base class for all commands. common logic should be implemented here
46 * @author Alexander Friese - initial contribution
49 public abstract class AbstractCommand extends BufferingResponseListener implements SolarEdgeCommand {
54 protected final Logger logger = LoggerFactory.getLogger(AbstractCommand.class);
59 protected final SolarEdgeConfiguration config;
64 private final Gson gson;
67 * status code of fulfilled request
69 private final CommunicationStatus communicationStatus;
72 * listener to provide updates to the WebInterface class
74 private final StatusUpdateListener listener;
83 public AbstractCommand(SolarEdgeConfiguration config, StatusUpdateListener listener) {
84 this.communicationStatus = new CommunicationStatus();
86 this.listener = listener;
87 this.gson = new Gson();
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());
103 * Log request failure
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);
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);
117 communicationStatus.setHttpCode(Code.INTERNAL_SERVER_ERROR);
120 logger.debug("Request failed");
125 public void onContent(@Nullable Response response, @Nullable ByteBuffer content) {
126 super.onContent(response, content);
127 logger.debug("received content, length: {}", getContentAsString().length());
131 public void performAction(HttpClient asyncclient) {
132 Request request = asyncclient.newRequest(getURL()).timeout(config.getAsyncTimeout(), TimeUnit.SECONDS);
134 // add authentication data for every request. Handling this here makes it obsolete to implement for each and
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);
144 // this is only relevant when using public API
145 request.param(PUBLIC_DATA_API_KEY_FIELD, config.getTokenOrApiKey());
148 prepareRequest(request).send(this);
152 * @return returns Http Status Code
154 public CommunicationStatus getCommunicationStatus() {
155 return communicationStatus;
159 * updates status of the registered listener.
161 protected final void updateListenerStatus() {
163 listener.update(communicationStatus);
164 } catch (Exception ex) {
165 // this should not happen
166 logger.warn("Exception caught: {}", ex.getMessage(), ex);
171 * concrete implementation has to prepare the requests with additional parameters, etc
173 * @param requestToPrepare the request to prepare
174 * @return prepared Request object
176 protected abstract Request prepareRequest(Request requestToPrepare);
179 * concrete implementation has to provide the URL
183 protected abstract String getURL();
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
193 * @throws JsonSyntaxException
195 protected <T> @Nullable T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
196 return gson.fromJson(json, classOfT);