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.shelly.internal.api;
15 import static org.openhab.binding.shelly.internal.util.ShellyUtils.getString;
17 import java.net.ConnectException;
18 import java.net.MalformedURLException;
19 import java.net.NoRouteToHostException;
20 import java.net.PortUnreachableException;
21 import java.net.SocketException;
22 import java.net.SocketTimeoutException;
23 import java.net.UnknownHostException;
24 import java.text.MessageFormat;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.TimeoutException;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
31 import com.google.gson.JsonSyntaxException;
34 * The {@link CarNetException} implements an extension to the standard Exception class. This allows to keep also the
35 * result of the last API call (e.g. including the http status code in the message).
37 * @author Markus Michels - Initial contribution
40 public class ShellyApiException extends Exception {
41 private static final long serialVersionUID = -5809459454769761821L;
43 private ShellyApiResult apiResult = new ShellyApiResult();
44 private static final String NONE = "none";
46 public ShellyApiException(Exception exception) {
50 public ShellyApiException(String message) {
54 public ShellyApiException(ShellyApiResult res) {
59 public ShellyApiException(String message, Exception exception) {
60 super(message, exception);
63 public ShellyApiException(ShellyApiResult result, Exception exception) {
69 public @Nullable String getMessage() {
70 return isEmpty() ? "" : nonNullString(super.getMessage());
74 public String toString() {
75 String message = nonNullString(super.getMessage()).replace("java.util.concurrent.ExecutionException: ", "")
76 .replace("java.net.", "");
77 String cause = getCauseClass().toString();
78 String url = apiResult.getUrl();
80 if (isUnknownHost()) {
81 String[] string = message.split(": "); // java.net.UnknownHostException: api.rach.io
82 message = MessageFormat.format("Unable to connect to {0} (Unknown host / Network down / Low signal)",
84 } else if (isMalformedURL()) {
85 message = "Invalid URL: " + url;
86 } else if (isJsonError()) {
87 message = getString(getMessage());
88 } else if (isTimeout()) {
89 message = "API Timeout for " + url;
90 } else if (!isConnectionError()) {
91 message = message + "(" + cause + ")";
94 message = apiResult.toString();
99 public boolean isJsonError() {
100 return getString(getMessage()).startsWith("Unable to create object of type");
103 public boolean isApiException() {
104 return getCauseClass() == ShellyApiException.class;
107 public boolean isTimeout() {
108 Class<?> extype = !isEmpty() ? getCauseClass() : null;
109 return (extype != null) && ((extype == TimeoutException.class) || extype == InterruptedException.class
110 || extype == SocketTimeoutException.class
111 || nonNullString(getMessage()).toLowerCase().contains("timeout"));
114 public boolean isConnectionError() {
115 Class<?> exType = getCauseClass();
116 return isUnknownHost() || isMalformedURL() || exType == ConnectException.class
117 || exType == SocketException.class || exType == PortUnreachableException.class
118 || exType == NoRouteToHostException.class;
121 public boolean isUnknownHost() {
122 return getCauseClass() == UnknownHostException.class;
125 public boolean isMalformedURL() {
126 return getCauseClass() == MalformedURLException.class;
129 public boolean isHttpAccessUnauthorized() {
130 return apiResult.isHttpAccessUnauthorized();
133 public boolean isJSONException() {
134 return getCauseClass() == JsonSyntaxException.class;
137 public ShellyApiResult getApiResult() {
141 private boolean isEmpty() {
142 return NONE.equals(nonNullString(super.getMessage()));
145 private static String nonNullString(@Nullable String s) {
146 return s != null ? s : "";
149 private Class<?> getCauseClass() {
150 Throwable cause = getCause();
151 if (cause != null && cause.getClass() == ExecutionException.class) {
152 cause = cause.getCause();
155 return cause.getClass();
157 return ShellyApiException.class;